2020-03-29 17:44:20 -06:00
|
|
|
/*
|
|
|
|
|
* NimBLEClient.cpp
|
|
|
|
|
*
|
|
|
|
|
* Created: on Jan 26 2020
|
|
|
|
|
* Author H2zero
|
2020-05-13 22:03:56 -06:00
|
|
|
*
|
2020-03-29 17:44:20 -06:00
|
|
|
* Originally:
|
|
|
|
|
* BLEClient.cpp
|
|
|
|
|
*
|
|
|
|
|
* Created on: Mar 22, 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_CENTRAL)
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# include "NimBLEClient.h"
|
|
|
|
|
# include "NimBLERemoteService.h"
|
|
|
|
|
# include "NimBLERemoteCharacteristic.h"
|
|
|
|
|
# include "NimBLEDevice.h"
|
|
|
|
|
# include "NimBLELog.h"
|
|
|
|
|
|
|
|
|
|
# if defined(CONFIG_NIMBLE_CPP_IDF)
|
|
|
|
|
# include "nimble/nimble_port.h"
|
|
|
|
|
# else
|
|
|
|
|
# include "nimble/porting/nimble/include/nimble/nimble_port.h"
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
# include <climits>
|
|
|
|
|
|
|
|
|
|
static const char* LOG_TAG = "NimBLEClient";
|
2020-03-29 17:44:20 -06:00
|
|
|
static NimBLEClientCallbacks defaultCallbacks;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Design
|
|
|
|
|
* ------
|
|
|
|
|
* When we perform a getService() request, we are asking the BLE server to return each of the services
|
|
|
|
|
* that it exposes. For each service, we receive a callback which contains details
|
|
|
|
|
* of the exposed service including its UUID.
|
|
|
|
|
*
|
|
|
|
|
* The objects we will invent for a NimBLEClient will be as follows:
|
|
|
|
|
* * NimBLERemoteService - A model of a remote service.
|
|
|
|
|
* * NimBLERemoteCharacteristic - A model of a remote characteristic
|
|
|
|
|
* * NimBLERemoteDescriptor - A model of a remote descriptor.
|
|
|
|
|
*
|
|
|
|
|
* Since there is a hierarchical relationship here, we will have the idea that from a NimBLERemoteService will own
|
2024-11-02 19:00:07 -06:00
|
|
|
* zero or more remote characteristics and a NimBLERemoteCharacteristic will own zero or more NimBLERemoteDescriptors.
|
2020-03-29 17:44:20 -06:00
|
|
|
*
|
2020-05-17 20:21:35 -06:00
|
|
|
* We will assume that a NimBLERemoteService contains a vector of owned characteristics
|
2024-11-02 19:00:07 -06:00
|
|
|
* and that a NimBLERemoteCharacteristic contains a vector of owned descriptors.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
|
|
|
|
|
2020-07-08 19:27:26 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Constructor, private - only callable by NimBLEDevice::createClient
|
|
|
|
|
* to ensure proper handling of the list of client objects.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
NimBLEClient::NimBLEClient(const NimBLEAddress& peerAddress)
|
|
|
|
|
: m_peerAddress(peerAddress),
|
|
|
|
|
m_lastErr{0},
|
|
|
|
|
m_connectTimeout{30000},
|
|
|
|
|
m_pTaskData{nullptr},
|
|
|
|
|
m_svcVec{},
|
|
|
|
|
m_pClientCallbacks{&defaultCallbacks},
|
|
|
|
|
m_connHandle{BLE_HS_CONN_HANDLE_NONE},
|
|
|
|
|
m_terminateFailCount{0},
|
|
|
|
|
m_deleteCallbacks{false},
|
|
|
|
|
m_connEstablished{false},
|
|
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
|
|
|
|
m_phyMask{BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK | BLE_GAP_LE_PHY_CODED_MASK},
|
|
|
|
|
# endif
|
|
|
|
|
m_connParams{16,
|
|
|
|
|
16,
|
|
|
|
|
BLE_GAP_INITIAL_CONN_ITVL_MIN,
|
|
|
|
|
BLE_GAP_INITIAL_CONN_ITVL_MAX,
|
|
|
|
|
BLE_GAP_INITIAL_CONN_LATENCY,
|
|
|
|
|
BLE_GAP_INITIAL_SUPERVISION_TIMEOUT,
|
|
|
|
|
BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
|
|
|
|
|
BLE_GAP_INITIAL_CONN_MAX_CE_LEN} {
|
2020-03-29 17:44:20 -06:00
|
|
|
} // NimBLEClient
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Destructor, private - only callable by NimBLEDevice::deleteClient
|
|
|
|
|
* to ensure proper disconnect and removal from device list.
|
|
|
|
|
*/
|
2020-05-13 22:03:56 -06:00
|
|
|
NimBLEClient::~NimBLEClient() {
|
|
|
|
|
// We may have allocated service references associated with this client.
|
2020-03-29 17:44:20 -06:00
|
|
|
// Before we are finished with the client, we must release resources.
|
2020-05-29 21:21:56 -06:00
|
|
|
deleteServices();
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (m_deleteCallbacks) {
|
2020-03-29 17:44:20 -06:00
|
|
|
delete m_pClientCallbacks;
|
|
|
|
|
}
|
|
|
|
|
} // ~NimBLEClient
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Delete all service objects created by this client and clear the vector.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2020-05-29 21:21:56 -06:00
|
|
|
void NimBLEClient::deleteServices() {
|
2020-03-29 17:44:20 -06:00
|
|
|
// Delete all the services.
|
2024-11-02 19:00:07 -06:00
|
|
|
for (auto& it : m_svcVec) {
|
2020-05-17 20:21:35 -06:00
|
|
|
delete it;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
std::vector<NimBLERemoteService*>().swap(m_svcVec);
|
2020-05-29 21:21:56 -06:00
|
|
|
} // deleteServices
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-02 19:00:07 -06:00
|
|
|
* @brief Delete a service by UUID from the local database to free resources.
|
|
|
|
|
* @param [in] uuid The UUID of the service to be deleted.
|
2020-05-29 21:21:56 -06:00
|
|
|
* @return Number of services left.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
size_t NimBLEClient::deleteService(const NimBLEUUID& uuid) {
|
2020-05-29 21:21:56 -06:00
|
|
|
// Delete the requested service.
|
2024-11-02 19:00:07 -06:00
|
|
|
for (auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
|
|
|
|
|
if ((*it)->getUUID() == uuid) {
|
2020-05-29 21:21:56 -06:00
|
|
|
delete *it;
|
2024-11-02 19:00:07 -06:00
|
|
|
m_svcVec.erase(it);
|
2020-05-29 21:21:56 -06:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
return m_svcVec.size();
|
2020-05-29 21:21:56 -06:00
|
|
|
} // deleteServices
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2020-07-30 10:06:10 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Connect to the BLE Server.
|
2022-07-31 11:00:12 -06:00
|
|
|
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
2020-07-30 10:06:10 -06:00
|
|
|
* have created and clears the vectors after successful connection.
|
|
|
|
|
* @return True on success.
|
|
|
|
|
*/
|
2022-07-31 11:00:12 -06:00
|
|
|
bool NimBLEClient::connect(bool deleteAttributes) {
|
|
|
|
|
return connect(m_peerAddress, deleteAttributes);
|
2020-07-30 10:04:34 -06:00
|
|
|
}
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Connect to an advertising device.
|
|
|
|
|
* @param [in] device The device to connect to.
|
2022-07-31 11:00:12 -06:00
|
|
|
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
2020-07-08 19:27:26 -06:00
|
|
|
* have created and clears the vectors after successful connection.
|
|
|
|
|
* @return True on success.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2022-07-31 11:00:12 -06:00
|
|
|
bool NimBLEClient::connect(NimBLEAdvertisedDevice* device, bool deleteAttributes) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NimBLEAddress address(device->getAddress());
|
2022-07-31 11:00:12 -06:00
|
|
|
return connect(address, deleteAttributes);
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-02 19:00:07 -06:00
|
|
|
* @brief Connect to a BLE Server by address.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @param [in] address The address of the server.
|
2022-07-31 11:00:12 -06:00
|
|
|
* @param [in] deleteAttributes If true this will delete any attribute objects this client may already\n
|
2020-07-08 19:27:26 -06:00
|
|
|
* have created and clears the vectors after successful connection.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @return True on success.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::connect(const NimBLEAddress& address, bool deleteAttributes) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (!NimBLEDevice::m_synced) {
|
2024-07-04 10:56:30 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Host reset, wait for sync.");
|
2020-03-29 17:44:20 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (isConnected() || m_connEstablished || m_pTaskData != nullptr) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Client busy, connected to %s, handle=%d", std::string(m_peerAddress).c_str(), getConnHandle());
|
2020-06-21 22:07:01 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-04 19:17:13 -06:00
|
|
|
const ble_addr_t* peerAddr = address.getBase();
|
2024-11-02 19:00:07 -06:00
|
|
|
if (ble_gap_conn_find_by_addr(peerAddr, NULL) == 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "A connection to %s already exists", address.toString().c_str());
|
2021-01-20 12:28:07 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (address.isNull()) {
|
2020-07-30 10:09:27 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Invalid peer address;(NULL)");
|
|
|
|
|
return false;
|
2021-01-20 12:28:07 -07:00
|
|
|
} else {
|
2020-07-30 10:09:27 -06:00
|
|
|
m_peerAddress = address;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2022-01-09 19:04:41 -07:00
|
|
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
2024-11-02 19:00:07 -06:00
|
|
|
BleTaskData taskData = {this, cur_task, 0, nullptr};
|
|
|
|
|
m_pTaskData = &taskData;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
2021-01-12 13:50:08 -07:00
|
|
|
do {
|
2024-11-02 19:00:07 -06:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
2024-09-29 15:59:42 -06:00
|
|
|
rc = ble_gap_ext_connect(NimBLEDevice::m_ownAddrType,
|
2024-07-04 19:17:13 -06:00
|
|
|
peerAddr,
|
2022-04-10 10:21:45 -06:00
|
|
|
m_connectTimeout,
|
|
|
|
|
m_phyMask,
|
2024-11-02 19:00:07 -06:00
|
|
|
&m_connParams,
|
|
|
|
|
&m_connParams,
|
|
|
|
|
&m_connParams,
|
2022-04-10 10:21:45 -06:00
|
|
|
NimBLEClient::handleGapEvent,
|
|
|
|
|
this);
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# else
|
|
|
|
|
rc = ble_gap_connect(NimBLEDevice::m_ownAddrType,
|
|
|
|
|
peerAddr,
|
|
|
|
|
m_connectTimeout,
|
|
|
|
|
&m_connParams,
|
|
|
|
|
NimBLEClient::handleGapEvent,
|
|
|
|
|
this);
|
|
|
|
|
# endif
|
2021-01-12 13:50:08 -07:00
|
|
|
switch (rc) {
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-01-12 13:50:08 -07:00
|
|
|
case BLE_HS_EBUSY:
|
2021-01-12 13:52:28 -07:00
|
|
|
// Scan was still running, stop it and try again
|
2021-01-12 13:50:08 -07:00
|
|
|
if (!NimBLEDevice::getScan()->stop()) {
|
2021-01-20 12:28:07 -07:00
|
|
|
rc = BLE_HS_EUNKNOWN;
|
2021-01-12 13:50:08 -07:00
|
|
|
}
|
|
|
|
|
break;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-01-12 13:50:08 -07:00
|
|
|
case BLE_HS_EDONE:
|
2021-01-12 13:52:28 -07:00
|
|
|
// A connection to this device already exists, do not connect twice.
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Already connected to device; addr=%s", std::string(m_peerAddress).c_str());
|
2021-01-20 12:28:07 -07:00
|
|
|
break;
|
2021-01-12 13:50:08 -07:00
|
|
|
|
|
|
|
|
case BLE_HS_EALREADY:
|
2022-07-31 11:00:12 -06:00
|
|
|
// Already attempting to connect to this device, cancel the previous
|
2021-01-12 13:52:28 -07:00
|
|
|
// attempt and report failure here so we don't get 2 connections.
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Already attempting to connect to %s - cancelling", std::string(m_peerAddress).c_str());
|
2021-01-12 13:50:08 -07:00
|
|
|
ble_gap_conn_cancel();
|
2021-01-20 12:28:07 -07:00
|
|
|
break;
|
2021-01-12 13:50:08 -07:00
|
|
|
|
|
|
|
|
default:
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG,
|
|
|
|
|
"Failed to connect to %s, rc=%d; %s",
|
2021-01-12 13:50:08 -07:00
|
|
|
std::string(m_peerAddress).c_str(),
|
2024-11-02 19:00:07 -06:00
|
|
|
rc,
|
|
|
|
|
NimBLEUtils::returnCodeToString(rc));
|
2021-01-20 12:28:07 -07:00
|
|
|
break;
|
2021-01-12 13:50:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (rc == BLE_HS_EBUSY);
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = rc;
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (rc != 0) {
|
2021-01-20 12:28:07 -07:00
|
|
|
m_pTaskData = nullptr;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# ifdef ulTaskNotifyValueClear
|
2022-01-09 19:04:41 -07:00
|
|
|
// Clear the task notification value to ensure we block
|
|
|
|
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
2024-11-02 19:00:07 -06:00
|
|
|
# endif
|
2021-01-13 22:00:39 -07:00
|
|
|
// Wait for the connect timeout time +1 second for the connection to complete
|
2024-11-02 19:00:07 -06:00
|
|
|
if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) {
|
2021-01-13 22:00:39 -07:00
|
|
|
m_pTaskData = nullptr;
|
|
|
|
|
// If a connection was made but no response from MTU exchange; disconnect
|
2024-11-02 19:00:07 -06:00
|
|
|
if (isConnected()) {
|
2021-01-13 22:00:39 -07:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connect timeout - no response");
|
|
|
|
|
disconnect();
|
|
|
|
|
} else {
|
2024-11-02 19:00:07 -06:00
|
|
|
// workaround; if the controller doesn't cancel the connection
|
|
|
|
|
// at the timeout, cancel it here.
|
2021-01-13 22:00:39 -07:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connect timeout - cancelling");
|
|
|
|
|
ble_gap_conn_cancel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
} else if (taskData.rc != 0) {
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = taskData.rc;
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connection failed; status=%d %s", taskData.rc, NimBLEUtils::returnCodeToString(taskData.rc));
|
|
|
|
|
// If the failure was not a result of a disconnection, make sure we disconnect now to avoid dangling connections
|
|
|
|
|
if (isConnected()) {
|
2021-01-20 12:28:07 -07:00
|
|
|
disconnect();
|
2021-01-12 13:52:28 -07:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
return false;
|
2021-01-12 13:52:28 -07:00
|
|
|
} else {
|
|
|
|
|
NIMBLE_LOGI(LOG_TAG, "Connection established");
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-04-13 19:13:51 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (deleteAttributes) {
|
2020-05-29 21:21:56 -06:00
|
|
|
deleteServices();
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-01-12 13:58:12 -07:00
|
|
|
m_connEstablished = true;
|
2020-05-13 22:03:56 -06:00
|
|
|
m_pClientCallbacks->onConnect(this);
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< connect()");
|
2021-01-14 10:21:25 -07:00
|
|
|
// Check if still connected before returning
|
|
|
|
|
return isConnected();
|
2020-03-29 17:44:20 -06:00
|
|
|
} // connect
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Initiate a secure connection (pair/bond) with the server.\n
|
|
|
|
|
* Called automatically when a characteristic or descriptor requires encryption or authentication to access it.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @return True on success.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @details This is a blocking function and should not be used in a callback.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-07-26 14:47:36 -06:00
|
|
|
bool NimBLEClient::secureConnection() const {
|
2022-10-23 19:15:57 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> secureConnection()");
|
2024-11-02 19:00:07 -06:00
|
|
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
|
|
|
|
BleTaskData taskData = {const_cast<NimBLEClient*>(this), cur_task, 0, nullptr};
|
|
|
|
|
int retryCount = 1;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-08-20 09:57:20 -06:00
|
|
|
do {
|
|
|
|
|
m_pTaskData = &taskData;
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
int rc = NimBLEDevice::startSecurity(m_connHandle);
|
|
|
|
|
if (rc != 0 && rc != BLE_HS_EALREADY) {
|
|
|
|
|
m_lastErr = rc;
|
2020-08-20 09:57:20 -06:00
|
|
|
m_pTaskData = nullptr;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# ifdef ulTaskNotifyValueClear
|
2022-01-09 19:04:41 -07:00
|
|
|
// Clear the task notification value to ensure we block
|
|
|
|
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
2024-11-02 19:00:07 -06:00
|
|
|
# endif
|
2020-08-20 09:57:20 -06:00
|
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
2020-08-21 11:46:45 -06:00
|
|
|
} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--);
|
2020-06-21 22:07:01 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (taskData.rc != 0) {
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = taskData.rc;
|
2022-10-23 19:15:57 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc);
|
2020-03-29 17:44:20 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2022-10-23 19:15:57 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< secureConnection: success");
|
2020-03-29 17:44:20 -06:00
|
|
|
return true;
|
2020-07-08 19:27:26 -06:00
|
|
|
} // secureConnection
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Disconnect from the peer.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @return True if the command was successfully sent.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::disconnect(uint8_t reason) {
|
|
|
|
|
int rc = ble_gap_terminate(m_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));
|
|
|
|
|
m_lastErr = rc;
|
|
|
|
|
return false;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
return true;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // disconnect
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# if CONFIG_BT_NIMBLE_EXT_ADV
|
2022-04-10 10:21:45 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Set the PHY types to use when connecting to a server.
|
|
|
|
|
* @param [in] mask A bitmask indicating what PHYS to connect with.\n
|
|
|
|
|
* The available bits are:
|
|
|
|
|
* * 0x01 BLE_GAP_LE_PHY_1M_MASK
|
|
|
|
|
* * 0x02 BLE_GAP_LE_PHY_2M_MASK
|
|
|
|
|
* * 0x04 BLE_GAP_LE_PHY_CODED_MASK
|
|
|
|
|
*/
|
|
|
|
|
void NimBLEClient::setConnectPhy(uint8_t mask) {
|
|
|
|
|
m_phyMask = mask;
|
|
|
|
|
}
|
2024-11-02 19:00:07 -06:00
|
|
|
# endif
|
2022-04-10 10:21:45 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2022-07-31 11:00:12 -06:00
|
|
|
* @brief Set the connection parameters to use when connecting to a server.
|
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.
|
|
|
|
|
* @param [in] scanInterval The scan interval to use when attempting to connect in 0.625ms units.
|
|
|
|
|
* @param [in] scanWindow The scan window to use when attempting to connect in 0.625ms units.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
void NimBLEClient::setConnectionParams(
|
|
|
|
|
uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout, uint16_t scanInterval, uint16_t scanWindow)
|
|
|
|
|
/*, uint16_t minConnEvtTime, uint16_t maxConnEvtTime)*/
|
2020-03-29 17:44:20 -06:00
|
|
|
{
|
2024-11-02 19:00:07 -06:00
|
|
|
m_connParams.itvl_min = minInterval;
|
|
|
|
|
m_connParams.itvl_max = maxInterval;
|
|
|
|
|
m_connParams.latency = latency;
|
|
|
|
|
m_connParams.supervision_timeout = timeout;
|
|
|
|
|
m_connParams.scan_itvl = scanInterval;
|
|
|
|
|
m_connParams.scan_window = scanWindow;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
|
|
|
|
// These are not used by NimBLE at this time - Must leave at defaults
|
2024-11-02 19:00:07 -06:00
|
|
|
// m_connParams.min_ce_len = minConnEvtTime; // Minimum length of connection event in 0.625ms units
|
|
|
|
|
// m_connParams.max_ce_len = maxConnEvtTime; // Maximum length of connection event in 0.625ms units
|
2020-07-08 19:27:26 -06:00
|
|
|
} // setConnectionParams
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Update the connection parameters:
|
|
|
|
|
* * Can only be used after a connection has been established.
|
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-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) {
|
|
|
|
|
ble_gap_upd_params params{.itvl_min = minInterval,
|
|
|
|
|
.itvl_max = maxInterval,
|
|
|
|
|
.latency = latency,
|
|
|
|
|
.supervision_timeout = timeout,
|
|
|
|
|
// These are not used by NimBLE at this time - leave at defaults
|
|
|
|
|
.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(m_connHandle, ¶ms);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
|
|
|
|
m_lastErr = rc;
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
return rc == 0;
|
|
|
|
|
} // updateConnParams
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2021-09-12 19:09:02 -06:00
|
|
|
/**
|
|
|
|
|
* @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 server the client is connected to.
|
|
|
|
|
* The Data Length Extension (DLE) allows to increase the Data Channel Payload from 27 bytes to up to 251 bytes.
|
|
|
|
|
* The server needs to support the Bluetooth 4.2 specifications, to be capable of DLE.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @param [in] txOctets The preferred number of payload octets to use (Range 0x001B-0x00FB).
|
2021-09-12 19:09:02 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::setDataLen(uint16_t txOctets) {
|
|
|
|
|
# if defined(CONFIG_NIMBLE_CPP_IDF) && !defined(ESP_IDF_VERSION) || \
|
|
|
|
|
(ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) < 432
|
|
|
|
|
return false;
|
|
|
|
|
# else
|
|
|
|
|
uint16_t txTime = (txOctets + 14) * 8;
|
|
|
|
|
int rc = ble_gap_set_data_len(m_connHandle, txOctets, txTime);
|
|
|
|
|
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-02 19:00:07 -06:00
|
|
|
return rc == 0;
|
|
|
|
|
# endif
|
|
|
|
|
} // setDataLen
|
2021-09-12 19:09:02 -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
|
|
|
/**
|
|
|
|
|
* @brief Get detailed information about the current peer connection.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @return A NimBLEConnInfo instance with the data, or a NULL 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-02 19:00:07 -06:00
|
|
|
NimBLEConnInfo NimBLEClient::getConnInfo() const {
|
|
|
|
|
NimBLEConnInfo connInfo{};
|
|
|
|
|
if (ble_gap_conn_find(m_connHandle, &connInfo.m_desc) != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connection info 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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return connInfo;
|
|
|
|
|
} // getConnInfo
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Set the timeout to wait for connection attempt to complete.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @param [in] time The number of milliseconds before timeout, default is 30 seconds.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2022-08-26 19:32:01 -06:00
|
|
|
void NimBLEClient::setConnectTimeout(uint32_t time) {
|
|
|
|
|
m_connectTimeout = time;
|
2020-07-08 19:27:26 -06:00
|
|
|
} // setConnectTimeout
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
2024-11-02 19:00:07 -06:00
|
|
|
* @brief Get the connection handle for this client.
|
|
|
|
|
* @return The connection handle.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
uint16_t NimBLEClient::getConnHandle() const {
|
|
|
|
|
return m_connHandle;
|
|
|
|
|
} // getConnHandle
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-06-04 11:37:24 -05:00
|
|
|
/**
|
|
|
|
|
* @brief Clear the connection information for this client.
|
|
|
|
|
* @note This is designed to be used to reset the connection information after
|
2024-11-02 19:00:07 -06:00
|
|
|
* calling setConnection(), and should not be used to disconnect from a peer.
|
|
|
|
|
* To disconnect from a peer, use disconnect().
|
2024-06-04 11:37:24 -05:00
|
|
|
*/
|
|
|
|
|
void NimBLEClient::clearConnection() {
|
2024-11-02 19:00:07 -06:00
|
|
|
m_connHandle = BLE_HS_CONN_HANDLE_NONE;
|
2024-06-04 11:37:24 -05:00
|
|
|
m_connEstablished = false;
|
2024-11-02 19:00:07 -06:00
|
|
|
m_peerAddress = NimBLEAddress{};
|
2024-06-04 11:37:24 -05:00
|
|
|
} // 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
|
2024-11-02 19:00:07 -06:00
|
|
|
* 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.
|
2024-06-04 11:37:24 -05:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::setConnection(const NimBLEConnInfo& connInfo) {
|
2024-06-04 11:37:24 -05:00
|
|
|
if (isConnected() || m_connEstablished) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Already connected");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
m_peerAddress = connInfo.getAddress();
|
|
|
|
|
m_connHandle = connInfo.getConnHandle();
|
2024-06-04 11:37:24 -05:00
|
|
|
m_connEstablished = true;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} // setConnection
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Set the connection information for this client.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @param [in] connHandle The connection handle.
|
2024-06-04 11:37:24 -05:00
|
|
|
* @note Sets the connection established flag to true.
|
|
|
|
|
* @note This is designed to be used when a connection is made outside of the
|
2024-11-02 19:00:07 -06:00
|
|
|
* 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.
|
2024-06-04 11:37:24 -05:00
|
|
|
* @note If the client is already connected to a peer, this will return false.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @note This will look up the peer address using the connection handle.
|
2024-06-04 11:37:24 -05:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::setConnection(uint16_t connHandle) {
|
2024-06-04 11:37:24 -05:00
|
|
|
// we weren't provided the peer address, look it up using ble_gap_conn_find
|
|
|
|
|
NimBLEConnInfo connInfo;
|
2024-11-02 19:00:07 -06:00
|
|
|
int rc = ble_gap_conn_find(connHandle, &connInfo.m_desc);
|
2024-06-04 11:37:24 -05:00
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return setConnection(connInfo);
|
|
|
|
|
} // setConnection
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Retrieve the address of the peer.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @return A NimBLEAddress instance with the peer address data.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-07-26 14:47:36 -06:00
|
|
|
NimBLEAddress NimBLEClient::getPeerAddress() const {
|
2020-03-29 17:44:20 -06:00
|
|
|
return m_peerAddress;
|
2020-07-30 10:04:34 -06:00
|
|
|
} // getPeerAddress
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Set the peer address.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @param [in] address The address of the peer that this client is connected or should connect to.
|
|
|
|
|
* @return True if successful.
|
2020-07-30 10:04:34 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::setPeerAddress(const NimBLEAddress& address) {
|
|
|
|
|
if (isConnected()) {
|
2020-07-30 10:04:34 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Cannot set peer address while connected");
|
2024-11-02 19:00:07 -06:00
|
|
|
return false;
|
2020-07-30 10:04:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_peerAddress = address;
|
2024-11-02 19:00:07 -06:00
|
|
|
return true;
|
2020-07-30 10:04:34 -06:00
|
|
|
} // setPeerAddress
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Ask the BLE server for the RSSI value.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @return The RSSI value or 0 if there was an error.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
int NimBLEClient::getRssi() const {
|
2020-03-29 17:44:20 -06:00
|
|
|
if (!isConnected()) {
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "getRssi(): Not connected");
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
int8_t rssi = 0;
|
|
|
|
|
int rc = ble_gap_conn_rssi(m_connHandle, &rssi);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Failed to read RSSI error code: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = rc;
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
return rssi;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // getRssi
|
|
|
|
|
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-22 20:13:52 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Get iterator to the beginning of the vector of remote service pointers.
|
|
|
|
|
* @return An iterator to the beginning of the vector of remote service pointers.
|
|
|
|
|
*/
|
|
|
|
|
std::vector<NimBLERemoteService*>::iterator NimBLEClient::begin() {
|
2024-11-02 19:00:07 -06:00
|
|
|
return m_svcVec.begin();
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-22 20:13:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get iterator to the end of the vector of remote service pointers.
|
|
|
|
|
* @return An iterator to the end of the vector of remote service pointers.
|
|
|
|
|
*/
|
|
|
|
|
std::vector<NimBLERemoteService*>::iterator NimBLEClient::end() {
|
2024-11-02 19:00:07 -06:00
|
|
|
return m_svcVec.end();
|
Add iterators to client remote attributes.
Add iterators for NimBLEScan: NimBLEadvertisedDevice, NimBLEClient: NimBLERemoteService, NimBLERemoteService: NimBLERemoteCharacteristic and NimBLERemoteCharacteristic: NimBLERemoteDescriptor
This is handy e.g. for showing every address of the advertised devices from a scan. To do so, first get a new scan and next:
```
for(auto pAdvertisedDevice: pBLEScan->getResults()) {
Serial.printf("Address is %s\n", std::string(pAdvertisedDevice->getAddress()).c_str());
}
```
Of course any other property of the advertised device can be shown (or looked up, if that is your use case)
Also this is handy e.g. for showing every UUID in a peripheral. To do so, first connect to a peripheral and next:
```
for(auto pService: *pClient) {
Serial.printf("Service UUID is %s\n", std::string(pService->getUUID()).c_str());
for(auto pCharacteristic: *pService) {
Serial.printf("Characteristic UUID is %s\n", std::string(pCharacteristic->getUUID()).c_str());
for(auto pDescriptor: *pCharacteristic) {
Serial.printf("Descriptor UUID is %s\n", std::string(pDescriptor->getUUID()).c_str());
}
}
}
```
Again of course any other property can be shown, or looked up.
2020-05-22 20:13:52 -06:00
|
|
|
}
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Get the service BLE Remote Service instance corresponding to the uuid.
|
|
|
|
|
* @param [in] uuid The UUID of the service being sought.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @return A pointer to the service or nullptr if not found.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
|
|
|
|
NimBLERemoteService* NimBLEClient::getService(const char* uuid) {
|
|
|
|
|
return getService(NimBLEUUID(uuid));
|
|
|
|
|
} // getService
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the service object corresponding to the uuid.
|
|
|
|
|
* @param [in] uuid The UUID of the service being sought.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @return A pointer to the service or nullptr if not found.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
NimBLERemoteService* NimBLEClient::getService(const NimBLEUUID& uuid) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (auto& it : m_svcVec) {
|
|
|
|
|
if (it->getUUID() == uuid) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
|
2020-05-17 20:21:35 -06:00
|
|
|
return it;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
size_t prevSize = m_svcVec.size();
|
|
|
|
|
if (retrieveServices(&uuid)) {
|
|
|
|
|
if (m_svcVec.size() > prevSize) {
|
|
|
|
|
return m_svcVec.back();
|
2020-05-23 10:27:32 -06:00
|
|
|
}
|
2020-12-28 15:40:01 -07:00
|
|
|
|
2022-01-18 14:48:07 -07:00
|
|
|
// If the request was successful but 16/32 bit uuid not found
|
2020-12-28 15:40:01 -07:00
|
|
|
// try again with the 128 bit uuid.
|
2024-11-02 19:00:07 -06:00
|
|
|
if (uuid.bitSize() == BLE_UUID_TYPE_16 || uuid.bitSize() == BLE_UUID_TYPE_32) {
|
2020-12-28 15:40:01 -07:00
|
|
|
NimBLEUUID uuid128(uuid);
|
|
|
|
|
uuid128.to128();
|
2024-11-02 19:00:07 -06:00
|
|
|
if (retrieveServices(&uuid128)) {
|
|
|
|
|
if (m_svcVec.size() > prevSize) {
|
|
|
|
|
return m_svcVec.back();
|
2022-02-14 20:18:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-18 14:48:07 -07:00
|
|
|
} else {
|
|
|
|
|
// If the request was successful but the 128 bit uuid not found
|
|
|
|
|
// try again with the 16 bit uuid.
|
|
|
|
|
NimBLEUUID uuid16(uuid);
|
|
|
|
|
uuid16.to16();
|
|
|
|
|
// if the uuid was 128 bit but not of the BLE base type this check will fail
|
|
|
|
|
if (uuid16.bitSize() == BLE_UUID_TYPE_16) {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (retrieveServices(&uuid16)) {
|
|
|
|
|
if (m_svcVec.size() > prevSize) {
|
|
|
|
|
return m_svcVec.back();
|
2022-02-14 20:18:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
2022-01-18 14:48:07 -07:00
|
|
|
}
|
2020-12-28 15:40:01 -07:00
|
|
|
}
|
2020-05-23 10:27:32 -06:00
|
|
|
}
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< getService: not found");
|
|
|
|
|
return nullptr;
|
|
|
|
|
} // getService
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Get a pointer to the vector of found services.
|
|
|
|
|
* @param [in] refresh If true the current services vector will be cleared and\n
|
|
|
|
|
* all services will be retrieved from the peripheral.\n
|
|
|
|
|
* If false the vector will be returned with the currently stored services.
|
|
|
|
|
* @return A pointer to the vector of available services.
|
2020-05-13 22:03:56 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
const std::vector<NimBLERemoteService*>& NimBLEClient::getServices(bool refresh) {
|
|
|
|
|
if (refresh) {
|
2020-05-29 21:21:56 -06:00
|
|
|
deleteServices();
|
2020-05-23 10:27:32 -06:00
|
|
|
if (!retrieveServices()) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Error: Failed to get services");
|
2024-11-02 19:00:07 -06:00
|
|
|
} else {
|
|
|
|
|
NIMBLE_LOGI(LOG_TAG, "Found %d services", m_svcVec.size());
|
2020-05-23 10:27:32 -06:00
|
|
|
}
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
return m_svcVec;
|
|
|
|
|
} // getServices
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2020-05-23 10:27:32 -06:00
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Retrieves the full database of attributes that the peripheral has available.
|
2022-04-16 20:32:01 -06:00
|
|
|
* @return True if successful.
|
2020-05-23 10:27:32 -06:00
|
|
|
*/
|
2022-04-16 20:32:01 -06:00
|
|
|
bool NimBLEClient::discoverAttributes() {
|
|
|
|
|
deleteServices();
|
2024-11-02 19:00:07 -06:00
|
|
|
if (!retrieveServices()) {
|
2022-04-16 20:32:01 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (auto svc : m_svcVec) {
|
2022-04-16 20:32:01 -06:00
|
|
|
if (!svc->retrieveCharacteristics()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (auto chr : svc->m_vChars) {
|
2022-04-16 20:32:01 -06:00
|
|
|
if (!chr->retrieveDescriptors()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-23 10:27:32 -06:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-16 20:32:01 -06:00
|
|
|
|
|
|
|
|
return true;
|
2020-07-08 19:27:26 -06:00
|
|
|
} // discoverAttributes
|
2020-05-23 10:27:32 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
/**
|
2024-11-02 19:00:07 -06:00
|
|
|
* @brief Ask the remote BLE server for its services.
|
|
|
|
|
* * Here we ask the server for its set of services and wait until we have received them all.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @return true on success otherwise false if an error occurred
|
2020-05-13 22:03:56 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::retrieveServices(const NimBLEUUID* uuidFilter) {
|
|
|
|
|
if (!isConnected()) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
int rc = 0;
|
2022-01-09 19:04:41 -07:00
|
|
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
2024-11-02 19:00:07 -06:00
|
|
|
BleTaskData taskData = {this, cur_task, 0, nullptr};
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (uuidFilter == nullptr) {
|
|
|
|
|
rc = ble_gattc_disc_all_svcs(m_connHandle, NimBLEClient::serviceDiscoveredCB, &taskData);
|
2020-05-23 10:27:32 -06:00
|
|
|
} else {
|
2024-11-02 19:00:07 -06:00
|
|
|
rc = ble_gattc_disc_svc_by_uuid(m_connHandle, uuidFilter->getBase(), NimBLEClient::serviceDiscoveredCB, &taskData);
|
2020-05-23 10:27:32 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = rc;
|
2020-03-29 17:44:20 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
# ifdef ulTaskNotifyValueClear
|
2022-01-09 19:04:41 -07:00
|
|
|
// Clear the task notification value to ensure we block
|
|
|
|
|
ulTaskNotifyValueClear(cur_task, ULONG_MAX);
|
2024-11-02 19:00:07 -06:00
|
|
|
# endif
|
2022-01-09 19:04:41 -07:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
// wait until we have all the services
|
2020-06-21 22:07:01 -06:00
|
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
2021-12-29 08:12:38 -07:00
|
|
|
m_lastErr = taskData.rc;
|
2020-06-21 22:07:01 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (taskData.rc == 0) {
|
2020-03-29 17:44:20 -06:00
|
|
|
return true;
|
2024-11-02 19:00:07 -06:00
|
|
|
} else {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG,
|
|
|
|
|
"Could not retrieve services, rc=%d %s",
|
|
|
|
|
taskData.rc,
|
|
|
|
|
NimBLEUtils::returnCodeToString(taskData.rc));
|
2020-03-29 17:44:20 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} // getServices
|
|
|
|
|
|
|
|
|
|
/**
|
2024-11-02 19:00:07 -06:00
|
|
|
* @brief Callback for the service discovery API function.
|
|
|
|
|
* @details When a service is found or there is none left or there was an error
|
2020-03-29 17:44:20 -06:00
|
|
|
* the API will call this and report findings.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
int NimBLEClient::serviceDiscoveredCB(uint16_t connHandle,
|
|
|
|
|
const struct ble_gatt_error* error,
|
|
|
|
|
const struct ble_gatt_svc* service,
|
|
|
|
|
void* arg) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG,
|
|
|
|
|
"Service Discovered >> status: %d handle: %d",
|
|
|
|
|
error->status,
|
|
|
|
|
(error->status == 0) ? service->start_handle : -1);
|
|
|
|
|
|
|
|
|
|
BleTaskData* pTaskData = (BleTaskData*)arg;
|
|
|
|
|
NimBLEClient* pClient = (NimBLEClient*)pTaskData->pATT;
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
// Make sure the service discovery is for this device
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->getConnHandle() != connHandle) {
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (error->status == 0) {
|
2020-06-21 22:07:01 -06:00
|
|
|
// Found a service - add it to the vector
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_svcVec.push_back(new NimBLERemoteService(pClient, service));
|
2020-06-21 22:07:01 -06:00
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (error->status == BLE_HS_EDONE) {
|
2020-06-21 22:07:01 -06:00
|
|
|
pTaskData->rc = 0;
|
|
|
|
|
} else {
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "serviceDiscoveredCB() rc=%d %s", error->status, NimBLEUtils::returnCodeToString(error->status));
|
2020-06-21 22:07:01 -06:00
|
|
|
pTaskData->rc = error->status;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-06-21 22:07:01 -06:00
|
|
|
|
|
|
|
|
xTaskNotifyGive(pTaskData->task);
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< Service Discovered");
|
2020-06-21 22:07:01 -06:00
|
|
|
return error->status;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the value of a specific characteristic associated with a specific service.
|
|
|
|
|
* @param [in] serviceUUID The service that owns the characteristic.
|
|
|
|
|
* @param [in] characteristicUUID The characteristic whose value we wish to read.
|
2024-11-02 19:00:07 -06:00
|
|
|
* @returns characteristic value or an empty value if not found.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
NimBLEAttValue NimBLEClient::getValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG,
|
|
|
|
|
">> getValue: serviceUUID: %s, characteristicUUID: %s",
|
|
|
|
|
serviceUUID.toString().c_str(),
|
|
|
|
|
characteristicUUID.toString().c_str());
|
|
|
|
|
|
|
|
|
|
NimBLEAttValue ret{};
|
|
|
|
|
auto pService = getService(serviceUUID);
|
|
|
|
|
if (pService != nullptr) {
|
|
|
|
|
auto pChar = pService->getCharacteristic(characteristicUUID);
|
|
|
|
|
if (pChar != nullptr) {
|
2020-03-29 17:44:20 -06:00
|
|
|
ret = pChar->readValue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-20 10:02:30 -07:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< getValue");
|
2020-03-29 17:44:20 -06:00
|
|
|
return ret;
|
|
|
|
|
} // getValue
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Set the value of a specific characteristic associated with a specific service.
|
|
|
|
|
* @param [in] serviceUUID The service that owns the characteristic.
|
|
|
|
|
* @param [in] characteristicUUID The characteristic whose value we wish to write.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @param [in] value The value to write to the characteristic.
|
2021-01-15 21:51:49 -07:00
|
|
|
* @param [in] response If true, uses write with response operation.
|
2020-03-29 17:44:20 -06:00
|
|
|
* @returns true if successful otherwise false
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::setValue(const NimBLEUUID& serviceUUID,
|
|
|
|
|
const NimBLEUUID& characteristicUUID,
|
|
|
|
|
const NimBLEAttValue& value,
|
|
|
|
|
bool response) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG,
|
|
|
|
|
">> setValue: serviceUUID: %s, characteristicUUID: %s",
|
|
|
|
|
serviceUUID.toString().c_str(),
|
|
|
|
|
characteristicUUID.toString().c_str());
|
|
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
auto pService = getService(serviceUUID);
|
|
|
|
|
if (pService != nullptr) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NimBLERemoteCharacteristic* pChar = pService->getCharacteristic(characteristicUUID);
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pChar != nullptr) {
|
2020-12-20 09:57:26 -07:00
|
|
|
ret = pChar->writeValue(value, response);
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "<< setValue");
|
|
|
|
|
return ret;
|
|
|
|
|
} // setValue
|
|
|
|
|
|
2020-09-15 22:09:30 -06:00
|
|
|
/**
|
|
|
|
|
* @brief Get the remote characteristic with the specified handle.
|
|
|
|
|
* @param [in] handle The handle of the desired characteristic.
|
|
|
|
|
* @returns The matching remote characteristic, nullptr otherwise.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
NimBLERemoteCharacteristic* NimBLEClient::getCharacteristic(uint16_t handle) {
|
|
|
|
|
for (const auto& svc : m_svcVec) {
|
|
|
|
|
if (svc->getStartHandle() <= handle && handle <= svc->getEndHandle()) {
|
|
|
|
|
for (const auto& chr : svc->m_vChars) {
|
|
|
|
|
if (chr->getHandle() == handle) {
|
|
|
|
|
return chr;
|
|
|
|
|
}
|
2020-09-15 22:09:30 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Get the current mtu of this connection.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @returns The MTU value.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-07-26 14:47:36 -06:00
|
|
|
uint16_t NimBLEClient::getMTU() const {
|
2024-11-02 19:00:07 -06:00
|
|
|
return ble_att_mtu(m_connHandle);
|
2020-07-08 19:27:26 -06:00
|
|
|
} // getMTU
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Handle a received GAP event.
|
2020-07-08 19:27:26 -06:00
|
|
|
* @param [in] event The event structure sent by the NimBLE stack.
|
|
|
|
|
* @param [in] arg A pointer to the client instance that registered for this callback.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
int NimBLEClient::handleGapEvent(struct ble_gap_event* event, void* arg) {
|
2022-08-27 08:28:15 -06:00
|
|
|
NimBLEClient* pClient = (NimBLEClient*)arg;
|
2024-11-02 19:00:07 -06:00
|
|
|
int rc = 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
switch (event->type) {
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_DISCONNECT: {
|
2021-01-12 13:56:29 -07:00
|
|
|
rc = event->disconnect.reason;
|
|
|
|
|
// If Host reset tell the device now before returning to prevent
|
|
|
|
|
// any errors caused by calling host functions before resyncing.
|
2024-11-02 19:00:07 -06:00
|
|
|
switch (rc) {
|
2021-01-12 13:56:29 -07:00
|
|
|
case BLE_HS_ECONTROLLER:
|
|
|
|
|
case BLE_HS_ETIMEOUT_HCI:
|
|
|
|
|
case BLE_HS_ENOTSYNCED:
|
|
|
|
|
case BLE_HS_EOS:
|
2024-07-04 10:56:30 -06:00
|
|
|
NIMBLE_LOGE(LOG_TAG, "Disconnect - host reset, rc=%d", rc);
|
2021-01-12 13:56:29 -07:00
|
|
|
NimBLEDevice::onReset(rc);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Check that the event is for this client.
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->disconnect.conn.conn_handle) {
|
2021-01-12 13:56:29 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2024-11-02 19:00:07 -06:00
|
|
|
|
2021-01-12 13:56:29 -07:00
|
|
|
break;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_terminateFailCount = 0;
|
2022-08-27 08:28:15 -06:00
|
|
|
NimBLEDevice::removeIgnored(pClient->m_peerAddress);
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
// If we received a connected event but did not get established
|
2021-01-12 13:52:28 -07:00
|
|
|
// then a disconnect event will be sent but we should not send it to the
|
|
|
|
|
// app for processing. Instead we will ensure the task is released
|
|
|
|
|
// and report the error.
|
2024-11-02 19:00:07 -06:00
|
|
|
if (!pClient->m_connEstablished) {
|
2021-01-12 13:52:28 -07:00
|
|
|
break;
|
2024-11-02 19:00:07 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2022-08-27 08:28:15 -06:00
|
|
|
pClient->m_connEstablished = false;
|
|
|
|
|
pClient->m_pClientCallbacks->onDisconnect(pClient, rc);
|
2020-06-21 22:07:01 -06:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // BLE_GAP_EVENT_DISCONNECT
|
|
|
|
|
|
|
|
|
|
case BLE_GAP_EVENT_CONNECT: {
|
2024-11-02 19:00:07 -06:00
|
|
|
// If we aren't waiting for this connection response we should drop the connection immediately.
|
|
|
|
|
if (pClient->isConnected() || pClient->m_pTaskData == nullptr) {
|
2021-01-12 13:50:08 -07:00
|
|
|
ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
2021-01-12 13:50:08 -07:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-01-12 13:50:08 -07:00
|
|
|
rc = event->connect.status;
|
|
|
|
|
if (rc == 0) {
|
2021-01-12 13:52:28 -07:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "Connected event");
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_connHandle = event->connect.conn_handle;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
rc = ble_gattc_exchange_mtu(pClient->m_connHandle, NULL, NULL);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "MTU exchange error; rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
|
2020-06-21 22:07:01 -06:00
|
|
|
break;
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2020-06-21 22:07:01 -06:00
|
|
|
|
2022-08-27 08:28:15 -06:00
|
|
|
// In the case of a multi-connecting device we ignore this device when
|
2020-06-21 22:07:01 -06:00
|
|
|
// scanning since we are already connected to it
|
2022-08-27 08:28:15 -06:00
|
|
|
NimBLEDevice::addIgnored(pClient->m_peerAddress);
|
2020-03-29 17:44:20 -06:00
|
|
|
} else {
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_connHandle = BLE_HS_CONN_HANDLE_NONE;
|
2020-06-21 22:07:01 -06:00
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2021-01-12 13:50:08 -07:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
|
|
|
|
} // BLE_GAP_EVENT_CONNECT
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
case BLE_GAP_EVENT_TERM_FAILURE: {
|
|
|
|
|
if (pClient->m_connHandle != event->term_failure.conn_handle) {
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
2024-11-02 19:00:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Connection termination failure; rc=%d - retrying", event->term_failure.status);
|
|
|
|
|
if (++pClient->m_terminateFailCount > 2) {
|
|
|
|
|
ble_hs_sched_reset(BLE_HS_ECONTROLLER);
|
|
|
|
|
} else {
|
|
|
|
|
ble_gap_terminate(event->term_failure.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
} // BLE_GAP_EVENT_TERM_FAILURE
|
|
|
|
|
|
|
|
|
|
case BLE_GAP_EVENT_NOTIFY_RX: {
|
|
|
|
|
if (pClient->m_connHandle != event->notify_rx.conn_handle) return 0;
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2021-01-12 13:58:12 -07:00
|
|
|
// If a notification comes before this flag is set we might
|
|
|
|
|
// access a vector while it is being cleared in connect()
|
2024-11-02 19:00:07 -06:00
|
|
|
if (!pClient->m_connEstablished) {
|
2021-01-12 13:58:12 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "Notify Received for handle: %d", event->notify_rx.attr_handle);
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (const auto& svc : pClient->m_svcVec) {
|
2020-06-21 22:07:01 -06:00
|
|
|
// Dont waste cycles searching services without this handle in its range
|
2024-11-02 19:00:07 -06:00
|
|
|
if (svc->getEndHandle() < event->notify_rx.attr_handle) {
|
2020-03-29 17:44:20 -06:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG,
|
|
|
|
|
"checking service %s for handle: %d",
|
|
|
|
|
svc->getUUID().toString().c_str(),
|
2021-01-12 13:52:28 -07:00
|
|
|
event->notify_rx.attr_handle);
|
2020-05-23 10:27:32 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (const auto& chr : svc->m_vChars) {
|
|
|
|
|
if (chr->getHandle() == event->notify_rx.attr_handle) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", chr->toString().c_str());
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
uint32_t data_len = OS_MBUF_PKTLEN(event->notify_rx.om);
|
|
|
|
|
chr->m_value.setValue(event->notify_rx.om->om_data, data_len);
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (chr->m_notifyCallback != nullptr) {
|
|
|
|
|
chr->m_notifyCallback(chr, event->notify_rx.om->om_data, data_len, !event->notify_rx.indication);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
|
|
|
|
} // BLE_GAP_EVENT_NOTIFY_RX
|
2020-05-13 22:03:56 -06:00
|
|
|
|
|
|
|
|
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->conn_update_req.conn_handle) {
|
2020-06-21 22:07:01 -06:00
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG,
|
|
|
|
|
"MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
|
2021-01-12 13:52:28 -07:00
|
|
|
event->conn_update_req.peer_params->itvl_min,
|
|
|
|
|
event->conn_update_req.peer_params->itvl_max,
|
|
|
|
|
event->conn_update_req.peer_params->latency,
|
|
|
|
|
event->conn_update_req.peer_params->supervision_timeout);
|
2020-04-13 19:13:51 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
rc = pClient->m_pClientCallbacks->onConnParamsUpdateRequest(pClient, event->conn_update_req.peer_params)
|
|
|
|
|
? 0
|
|
|
|
|
: BLE_ERR_CONN_PARMS;
|
2020-04-13 19:13:51 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (!rc && event->type == BLE_GAP_EVENT_CONN_UPDATE_REQ) {
|
|
|
|
|
event->conn_update_req.self_params->itvl_min = pClient->m_connParams.itvl_min;
|
|
|
|
|
event->conn_update_req.self_params->itvl_max = pClient->m_connParams.itvl_max;
|
|
|
|
|
event->conn_update_req.self_params->latency = pClient->m_connParams.latency;
|
|
|
|
|
event->conn_update_req.self_params->supervision_timeout = pClient->m_connParams.supervision_timeout;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-04-13 19:13:51 -06:00
|
|
|
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "%s peer params", (rc == 0) ? "Accepted" : "Rejected");
|
2020-03-29 17:44:20 -06:00
|
|
|
return rc;
|
|
|
|
|
} // BLE_GAP_EVENT_CONN_UPDATE_REQ, BLE_GAP_EVENT_L2CAP_UPDATE_REQ
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_CONN_UPDATE: {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->conn_update.conn_handle) {
|
2020-06-21 22:07:01 -06:00
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2024-11-02 19:00:07 -06:00
|
|
|
if (event->conn_update.status == 0) {
|
2020-03-29 17:44:20 -06:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "Connection parameters updated.");
|
|
|
|
|
} else {
|
|
|
|
|
NIMBLE_LOGE(LOG_TAG, "Update connection parameters failed.");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
} // BLE_GAP_EVENT_CONN_UPDATE
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_ENC_CHANGE: {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->enc_change.conn_handle) {
|
2020-06-21 22:07:01 -06:00
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (event->enc_change.status == 0 ||
|
|
|
|
|
event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
2022-08-27 08:28:15 -06:00
|
|
|
NimBLEConnInfo peerInfo;
|
|
|
|
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &peerInfo.m_desc);
|
2024-06-06 19:36:14 -06:00
|
|
|
if (rc != 0) {
|
|
|
|
|
rc = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-08-21 11:46:45 -06:00
|
|
|
if (event->enc_change.status == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING)) {
|
2020-08-20 09:57:20 -06:00
|
|
|
// Key is missing, try deleting.
|
2022-08-27 08:28:15 -06:00
|
|
|
ble_store_util_delete_peer(&peerInfo.m_desc.peer_id_addr);
|
2020-03-29 17:44:20 -06:00
|
|
|
} else {
|
2022-08-27 08:28:15 -06:00
|
|
|
pClient->m_pClientCallbacks->onAuthenticationComplete(peerInfo);
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-06-21 22:07:01 -06:00
|
|
|
rc = event->enc_change.status;
|
|
|
|
|
break;
|
2024-11-02 19:00:07 -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: {
|
|
|
|
|
NimBLEConnInfo peerInfo;
|
|
|
|
|
rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &peerInfo.m_desc);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
rc = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pClient->m_pClientCallbacks->onIdentity(peerInfo);
|
|
|
|
|
break;
|
|
|
|
|
} // BLE_GAP_EVENT_IDENTITY_RESOLVED
|
|
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
case BLE_GAP_EVENT_MTU: {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->mtu.conn_handle) {
|
2020-06-21 22:07:01 -06:00
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d", event->mtu.conn_handle, event->mtu.value);
|
2020-06-21 22:07:01 -06:00
|
|
|
rc = 0;
|
|
|
|
|
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_PASSKEY_ACTION: {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_connHandle != event->passkey.conn_handle) {
|
2020-03-29 17:44:20 -06:00
|
|
|
return 0;
|
2024-11-02 19:00:07 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-06-06 19:36:14 -06:00
|
|
|
NimBLEConnInfo peerInfo;
|
|
|
|
|
rc = ble_gap_conn_find(event->passkey.conn_handle, &peerInfo.m_desc);
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
rc = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2024-06-06 19:36:14 -06:00
|
|
|
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);
|
2024-11-02 19:00:07 -06:00
|
|
|
pClient->m_pClientCallbacks->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-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(LOG_TAG, "OOB request received");
|
|
|
|
|
// TODO: Handle out of band pairing
|
|
|
|
|
// struct ble_sm_io pkey;
|
|
|
|
|
// pkey.action = BLE_SM_IOACT_OOB;
|
|
|
|
|
// pClient->onOobPairingRequest(pkey.oob);
|
|
|
|
|
// rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
|
|
|
|
|
// NIMBLE_LOGD(LOG_TAG, "ble_sm_inject_io result: %d", rc);
|
2020-03-29 17:44:20 -06:00
|
|
|
} else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
|
|
|
|
|
NIMBLE_LOGD(LOG_TAG, "Enter the passkey");
|
2024-06-06 19:36:14 -06:00
|
|
|
pClient->m_pClientCallbacks->onPassKeyEntry(peerInfo);
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
} // BLE_GAP_EVENT_PASSKEY_ACTION
|
2020-05-13 22:03:56 -06:00
|
|
|
|
2020-03-29 17:44:20 -06:00
|
|
|
default: {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} // Switch
|
2020-06-21 22:07:01 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_pTaskData != nullptr) {
|
2022-08-27 08:28:15 -06:00
|
|
|
pClient->m_pTaskData->rc = rc;
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClient->m_pTaskData->task) {
|
2022-08-27 08:28:15 -06:00
|
|
|
xTaskNotifyGive(pClient->m_pTaskData->task);
|
2021-01-12 13:54:53 -07:00
|
|
|
}
|
2022-08-27 08:28:15 -06:00
|
|
|
pClient->m_pTaskData = nullptr;
|
2020-06-21 22:07:01 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // handleGapEvent
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Are we connected to a server?
|
|
|
|
|
* @return True if we are connected and false if we are not connected.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
bool NimBLEClient::isConnected() const {
|
|
|
|
|
return m_connHandle != BLE_HS_CONN_HANDLE_NONE;
|
2020-03-29 17:44:20 -06:00
|
|
|
} // isConnected
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-08 19:27:26 -06:00
|
|
|
* @brief Set the callbacks that will be invoked when events are received.
|
|
|
|
|
* @param [in] pClientCallbacks A pointer to a class to receive the event callbacks.
|
|
|
|
|
* @param [in] deleteCallbacks If true this will delete the callback class sent when the client is destructed.
|
2020-03-29 17:44:20 -06:00
|
|
|
*/
|
|
|
|
|
void NimBLEClient::setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) {
|
2024-11-02 19:00:07 -06:00
|
|
|
if (pClientCallbacks != nullptr) {
|
2020-05-13 22:03:56 -06:00
|
|
|
m_pClientCallbacks = pClientCallbacks;
|
2024-11-02 19:00:07 -06:00
|
|
|
m_deleteCallbacks = deleteCallbacks;
|
2020-05-13 22:03:56 -06:00
|
|
|
} else {
|
|
|
|
|
m_pClientCallbacks = &defaultCallbacks;
|
2024-11-02 19:00:07 -06:00
|
|
|
m_deleteCallbacks = false;
|
2020-05-13 22:03:56 -06:00
|
|
|
}
|
2020-03-29 17:44:20 -06:00
|
|
|
} // setClientCallbacks
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Return a string representation of this client.
|
|
|
|
|
* @return A string representation of this client.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
std::string NimBLEClient::toString() const {
|
|
|
|
|
std::string res = "peer address: " + m_peerAddress.toString();
|
|
|
|
|
res += "\nServices:\n";
|
2020-05-17 20:21:35 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
for (const auto& it : m_svcVec) {
|
2020-05-17 20:21:35 -06:00
|
|
|
res += it->toString() + "\n";
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
} // toString
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
static const char* CB_TAG = "NimBLEClientCallbacks";
|
2021-12-29 08:12:38 -07:00
|
|
|
/**
|
|
|
|
|
* @brief Get the last error code reported by the NimBLE host
|
|
|
|
|
* @return int, the NimBLE error code.
|
|
|
|
|
*/
|
2024-11-02 19:00:07 -06:00
|
|
|
int NimBLEClient::getLastError() const {
|
2021-12-29 08:12:38 -07:00
|
|
|
return m_lastErr;
|
|
|
|
|
} // getLastError
|
|
|
|
|
|
2020-04-13 19:13:51 -06:00
|
|
|
void NimBLEClientCallbacks::onConnect(NimBLEClient* pClient) {
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(CB_TAG, "onConnect: default");
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2022-08-26 19:51:19 -06:00
|
|
|
void NimBLEClientCallbacks::onDisconnect(NimBLEClient* pClient, int reason) {
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(CB_TAG, "onDisconnect: default");
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2020-04-13 19:13:51 -06:00
|
|
|
bool NimBLEClientCallbacks::onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
2024-11-02 19:00:07 -06:00
|
|
|
NIMBLE_LOGD(CB_TAG, "onConnParamsUpdateRequest: default");
|
2020-04-13 19:13:51 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
void NimBLEClientCallbacks::onPassKeyEntry(NimBLEConnInfo& connInfo) {
|
|
|
|
|
NIMBLE_LOGD(CB_TAG, "onPassKeyEntry: default: 123456");
|
2024-06-06 19:36:14 -06:00
|
|
|
NimBLEDevice::injectPassKey(connInfo, 123456);
|
2024-11-02 19:00:07 -06:00
|
|
|
} // onPassKeyEntry
|
2020-03-29 17:44:20 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
void NimBLEClientCallbacks::onAuthenticationComplete(NimBLEConnInfo& connInfo) {
|
|
|
|
|
NIMBLE_LOGD(CB_TAG, "onAuthenticationComplete: default");
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
2024-06-06 19:36:14 -06:00
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
void NimBLEClientCallbacks::onIdentity(NimBLEConnInfo& connInfo) {
|
|
|
|
|
NIMBLE_LOGD(CB_TAG, "onIdentity: default");
|
2024-06-12 09:26:10 -06:00
|
|
|
} // onIdentity
|
|
|
|
|
|
2024-11-02 19:00:07 -06:00
|
|
|
void NimBLEClientCallbacks::onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin) {
|
|
|
|
|
NIMBLE_LOGD(CB_TAG, "onConfirmPasskey: default: true");
|
2024-09-29 15:59:42 -06:00
|
|
|
NimBLEDevice::injectConfirmPasskey(connInfo, true);
|
2020-03-29 17:44:20 -06:00
|
|
|
}
|
|
|
|
|
|
2021-09-06 21:14:43 -06:00
|
|
|
#endif /* CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL */
|