Replace semaphores with task notifications. (#9)

* Replace all semaphores with task notifications.

* use critical sections to prevent concurrent data access.

* Ensure scan stop has been called before connecting.

* Optimize and cleanup

* Add template casting to NimBLERemoteDescriptor::readValue()

* Removed storage of the descriptor value read as it did not serve any purpose.
This commit is contained in:
h2zero 2020-06-21 22:07:01 -06:00 committed by GitHub
parent 5bc9d59646
commit f5541d18de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 368 additions and 401 deletions

View file

@ -18,7 +18,6 @@
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#include "NimBLEClient.h"
#include "NimBLEUtils.h"
#include "NimBLEDevice.h"
#include "NimBLELog.h"
@ -54,7 +53,10 @@ NimBLEClient::NimBLEClient()
m_pClientCallbacks = &defaultCallbacks;
m_conn_id = BLE_HS_CONN_HANDLE_NONE;
m_isConnected = false;
m_waitingToConnect = false;
m_connectTimeout = 30000;
m_deleteCallbacks = false;
m_pTaskData = nullptr;
m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
@ -157,6 +159,10 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
return false;
}
if(!NimBLEDevice::getScan()->stop()) {
return false;
}
int rc = 0;
m_peerAddress = address;
@ -164,7 +170,8 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
memcpy(&peerAddrt.val, address.getNative(),6);
peerAddrt.type = type;
m_semaphoreOpenEvt.take("connect");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
m_pTaskData = &taskData;
/** Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
* timeout (default value of m_connectTimeout).
@ -174,7 +181,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &peerAddrt, m_connectTimeout, &m_pConnParams,
NimBLEClient::handleGapEvent, this);
if(rc == BLE_HS_EBUSY) {
vTaskDelay(1);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
}while(rc == BLE_HS_EBUSY);
@ -184,17 +191,17 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
type,
m_peerAddress.toString().c_str(),
rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreOpenEvt.give();
m_pTaskData = nullptr;
m_waitingToConnect = false;
return false;
}
m_waitingToConnect = true;
rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
// Wait for the connection to complete.
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(rc != 0){
if(taskData.rc != 0){
return false;
}
@ -216,17 +223,18 @@ bool NimBLEClient::connect(const NimBLEAddress &address, uint8_t type, bool refr
* @return True on success.
*/
bool NimBLEClient::secureConnection() {
m_semeaphoreSecEvt.take("secureConnection");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
m_pTaskData = &taskData;
int rc = NimBLEDevice::startSecurity(m_conn_id);
if(rc != 0){
m_semeaphoreSecEvt.give();
m_pTaskData = nullptr;
return false;
}
rc = m_semeaphoreSecEvt.wait("secureConnection");
if(rc != 0){
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc != 0){
return false;
}
@ -458,30 +466,31 @@ bool NimBLEClient::retrieveServices(const NimBLEUUID *uuid_filter) {
*/
NIMBLE_LOGD(LOG_TAG, ">> retrieveServices");
int rc = 0;
if(!m_isConnected){
NIMBLE_LOGE(LOG_TAG, "Disconnected, could not retrieve services -aborting");
return false;
}
m_semaphoreSearchCmplEvt.take("retrieveServices");
int rc = 0;
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, this);
rc = ble_gattc_disc_all_svcs(m_conn_id, NimBLEClient::serviceDiscoveredCB, &taskData);
} else {
rc = ble_gattc_disc_svc_by_uuid(m_conn_id, &uuid_filter->getNative()->u,
NimBLEClient::serviceDiscoveredCB, this);
NimBLEClient::serviceDiscoveredCB, &taskData);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_svcs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreSearchCmplEvt.give();
return false;
}
// wait until we have all the services
if(m_semaphoreSearchCmplEvt.wait("retrieveServices") == 0){
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc == 0){
NIMBLE_LOGD(LOG_TAG, "<< retrieveServices");
return true;
}
@ -505,41 +514,34 @@ int NimBLEClient::serviceDiscoveredCB(
NIMBLE_LOGD(LOG_TAG,"Service Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? service->start_handle : -1);
NimBLEClient *peer = (NimBLEClient*)arg;
int rc=0;
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLEClient *client = (NimBLEClient*)pTaskData->pATT;
// Make sure the service discovery is for this device
if(peer->getConnId() != conn_handle){
if(client->getConnId() != conn_handle){
return 0;
}
switch (error->status) {
case 0: {
if(error->status == 0) {
// Found a service - add it to the vector
NimBLERemoteService* pRemoteService = new NimBLERemoteService(peer, service);
peer->m_servicesVector.push_back(pRemoteService);
break;
}
case BLE_HS_EDONE:{
// All services discovered; start discovering characteristics.
//NIMBLE_LOGD(LOG_TAG,"Giving search semaphore - completed");
peer->m_semaphoreSearchCmplEvt.give(0);
rc = 0;
break;
}
default:
// Error; abort discovery.
rc = error->status;
break;
NimBLERemoteService* pRemoteService = new NimBLERemoteService(client, service);
client->m_servicesVector.push_back(pRemoteService);
return 0;
}
if (rc != 0) {
// pass non-zero to semaphore on error to indicate an error finding services
peer->m_semaphoreSearchCmplEvt.give(1);
if(error->status == BLE_HS_EDONE) {
pTaskData->rc = 0;
} else {
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
error->status,
NimBLEUtils::returnCodeToString(error->status));
pTaskData->rc = error->status;
}
NIMBLE_LOGD(LOG_TAG,"<< Service Discovered. status: %d", rc);
return rc;
xTaskNotifyGive(pTaskData->task);
NIMBLE_LOGD(LOG_TAG,"<< << Service Discovered");
return error->status;
}
@ -611,15 +613,11 @@ uint16_t NimBLEClient::getMTU() {
* @param [in] arg = pointer to the client instance
*/
/*STATIC*/ int NimBLEClient::handleGapEvent(struct ble_gap_event *event, void *arg) {
NimBLEClient* client = (NimBLEClient*)arg;
//struct ble_gap_conn_desc desc;
//struct ble_hs_adv_fields fields;
int rc;
NIMBLE_LOGD(LOG_TAG, "Got Client event %s", NimBLEUtils::gapEventToString(event->type));
// Execute handler code based on the type of event received.
switch(event->type) {
case BLE_GAP_EVENT_DISCONNECT: {
@ -636,9 +634,6 @@ uint16_t NimBLEClient::getMTU() {
NIMBLE_LOGI(LOG_TAG, "disconnect; reason=%d, %s", event->disconnect.reason,
NimBLEUtils::returnCodeToString(event->disconnect.reason));
//print_conn_desc(&event->disconnect.conn);
//MODLOG_DFLT(INFO, "\n");
// If Host reset tell the device now before returning to prevent
// any errors caused by calling host functions before resyncing.
@ -655,15 +650,9 @@ uint16_t NimBLEClient::getMTU() {
}
//client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
// Indicate a non-success return value to any semaphores waiting
client->m_semaphoreOpenEvt.give(1);
client->m_semaphoreSearchCmplEvt.give(1);
client->m_semeaphoreSecEvt.give(1);
client->m_pClientCallbacks->onDisconnect(client);
return 0;
rc = event->disconnect.reason;
break;
} // BLE_GAP_EVENT_DISCONNECT
case BLE_GAP_EVENT_CONNECT: {
@ -683,31 +672,24 @@ uint16_t NimBLEClient::getMTU() {
client->m_conn_id = event->connect.conn_handle;
// rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
// assert(rc == 0);
// print_conn_desc(&desc);
// MODLOG_DFLT(INFO, "\n");
// In the case of a multiconnecting device we ignore this device when
// scanning since we are already connected to it
NimBLEDevice::addIgnored(client->m_peerAddress);
rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL,NULL);
if(rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_exchange_mtu: rc=%d %s",rc,
NimBLEUtils::returnCodeToString(rc));
// if error getting mtu indicate a connection error.
client->m_semaphoreOpenEvt.give(rc);
break;
}
// In the case of a multiconnecting device we ignore this device when
// scanning since we are already connected to it
NimBLEDevice::addIgnored(client->m_peerAddress);
} else {
// Connection attempt failed
NIMBLE_LOGE(LOG_TAG, "Error: Connection failed; status=%d %s",
event->connect.status,
NimBLEUtils::returnCodeToString(event->connect.status));
client->m_isConnected = false;
client->m_semaphoreOpenEvt.give(event->connect.status);
rc = event->connect.status;
break;
}
return 0;
} // BLE_GAP_EVENT_CONNECT
@ -719,7 +701,7 @@ uint16_t NimBLEClient::getMTU() {
NIMBLE_LOGD(LOG_TAG, "Notify Recieved for handle: %d",event->notify_rx.attr_handle);
for(auto &it: client->m_servicesVector) {
// Dont waste cycles searching services without this handle in their range
// Dont waste cycles searching services without this handle in its range
if(it->getEndHandle() < event->notify_rx.attr_handle) {
continue;
}
@ -738,11 +720,10 @@ uint16_t NimBLEClient::getMTU() {
if(characteristic != cVector->cend()) {
NIMBLE_LOGD(LOG_TAG, "Got Notification for characteristic %s", (*characteristic)->toString().c_str());
if((*characteristic)->m_semaphoreReadCharEvt.take(0, "notifyValue")) {
portENTER_CRITICAL(&(*characteristic)->m_valMux);
(*characteristic)->m_value = std::string((char *)event->notify_rx.om->om_data, event->notify_rx.om->om_len);
(*characteristic)->m_timestamp = time(nullptr);
(*characteristic)->m_semaphoreReadCharEvt.give();
}
portEXIT_CRITICAL(&(*characteristic)->m_valMux);
if ((*characteristic)->m_notifyCallback != nullptr) {
NIMBLE_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s",
@ -761,7 +742,7 @@ uint16_t NimBLEClient::getMTU() {
case BLE_GAP_EVENT_CONN_UPDATE_REQ:
case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: {
if(client->m_conn_id != event->conn_update_req.conn_handle){
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
return 0;
}
NIMBLE_LOGD(LOG_TAG, "Peer requesting to update connection parameters");
NIMBLE_LOGD(LOG_TAG, "MinInterval: %d, MaxInterval: %d, Latency: %d, Timeout: %d",
@ -787,7 +768,7 @@ uint16_t NimBLEClient::getMTU() {
case BLE_GAP_EVENT_CONN_UPDATE: {
if(client->m_conn_id != event->conn_update.conn_handle){
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
return 0;
}
if(event->conn_update.status == 0) {
NIMBLE_LOGI(LOG_TAG, "Connection parameters updated.");
@ -799,7 +780,7 @@ uint16_t NimBLEClient::getMTU() {
case BLE_GAP_EVENT_ENC_CHANGE: {
if(client->m_conn_id != event->enc_change.conn_handle){
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
return 0;
}
if(event->enc_change.status == 0) {
@ -814,23 +795,23 @@ uint16_t NimBLEClient::getMTU() {
}
}
client->m_semeaphoreSecEvt.give(event->enc_change.status);
return 0;
rc = event->enc_change.status;
break;
} //BLE_GAP_EVENT_ENC_CHANGE
case BLE_GAP_EVENT_MTU: {
if(client->m_conn_id != event->mtu.conn_handle){
return 0; //BLE_HS_ENOTCONN BLE_ATT_ERR_INVALID_HANDLE
return 0;
}
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
event->mtu.conn_handle,
event->mtu.value);
client->m_semaphoreOpenEvt.give(0);
return 0;
rc = 0;
break;
} // BLE_GAP_EVENT_MTU
case BLE_GAP_EVENT_PASSKEY_ACTION: {
struct ble_sm_io pkey = {0};
struct ble_sm_io pkey = {0,0};
if(client->m_conn_id != event->passkey.conn_handle)
return 0;
@ -891,6 +872,14 @@ uint16_t NimBLEClient::getMTU() {
return 0;
}
} // Switch
if(client->m_pTaskData != nullptr) {
client->m_pTaskData->rc = rc;
xTaskNotifyGive(client->m_pTaskData->task);
client->m_pTaskData = nullptr;
}
return 0;
} // handleGapEvent

View file

@ -22,17 +22,13 @@
#include "NimBLEAddress.h"
#include "NimBLEUUID.h"
#include "NimBLEUtils.h"
#include "NimBLEAdvertisedDevice.h"
#include "NimBLERemoteService.h"
#include <vector>
#include <string>
typedef struct {
const NimBLEUUID *uuid;
const void *attribute;
} disc_filter_t;
class NimBLERemoteService;
class NimBLEClientCallbacks;
class NimBLEAdvertisedDevice;
@ -89,14 +85,12 @@ private:
NimBLEAddress m_peerAddress = NimBLEAddress("");
uint16_t m_conn_id;
bool m_isConnected = false;
bool m_waitingToConnect =false;
bool m_deleteCallbacks = true;
bool m_isConnected;
bool m_waitingToConnect;
bool m_deleteCallbacks;
int32_t m_connectTimeout;
NimBLEClientCallbacks* m_pClientCallbacks = nullptr;
FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt");
FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt");
FreeRTOS::Semaphore m_semeaphoreSecEvt = FreeRTOS::Semaphore("Security");
NimBLEClientCallbacks* m_pClientCallbacks;
ble_task_data_t *m_pTaskData;
std::vector<NimBLERemoteService*> m_servicesVector;

View file

@ -60,6 +60,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
m_pRemoteService = pRemoteService;
m_notifyCallback = nullptr;
m_timestamp = 0;
m_valMux = portMUX_INITIALIZER_UNLOCKED;
} // NimBLERemoteCharacteristic
@ -67,7 +68,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
*@brief Destructor.
*/
NimBLERemoteCharacteristic::~NimBLERemoteCharacteristic() {
deleteDescriptors(); // Release resources for any descriptor information we may have allocated.
deleteDescriptors();
} // ~NimBLERemoteCharacteristic
/*
@ -147,12 +148,12 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? dsc->handle : -1);
disc_filter_t *filter = (disc_filter_t*)arg;
NimBLEUUID *uuid_filter = (NimBLEUUID*)filter->uuid;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)filter->attribute;
desc_filter_t *filter = (desc_filter_t*)arg;
const NimBLEUUID *uuid_filter = filter->uuid;
ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
int rc=0;
// Make sure the discovery is for this device
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0;
}
@ -172,7 +173,7 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
rc = BLE_HS_EDONE;
}
}
// Found a descriptor - add it to the vector
NimBLERemoteDescriptor* pNewRemoteDescriptor = new NimBLERemoteDescriptor(characteristic, dsc);
characteristic->m_descriptorVector.push_back(pNewRemoteDescriptor);
break;
@ -182,18 +183,20 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
break;
}
/** If rc == BLE_HS_EDONE, release the semaphore with a success error code and stop the discovery process.
/** If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
* If we get any other error code tell the application to abort by returning non-zero in the semaphore rc.
* If we get any other error code tell the application to abort by returning non-zero in the rc.
*/
if (rc == BLE_HS_EDONE) {
characteristic->m_semaphoreGetDescEvt.give(0);
pTaskData->rc = 0;
xTaskNotifyGive(pTaskData->task);
} else if(rc != 0) {
/* Error; abort discovery. */
// pass error code to semaphore waiting
characteristic->m_semaphoreGetDescEvt.give(rc);
// Error; abort discovery.
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
}
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", rc);
NIMBLE_LOGD(LOG_TAG,"<< Descriptor Discovered. status: %d", pTaskData->rc);
return rc;
}
@ -206,11 +209,8 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
int rc = 0;
disc_filter_t filter;
filter.uuid = uuid_filter;
filter.attribute = this;
m_semaphoreGetDescEvt.take("retrieveDescriptors");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
desc_filter_t filter = {uuid_filter, &taskData};
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
m_handle,
@ -219,11 +219,12 @@ bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filt
&filter);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreGetDescEvt.give();
return false;
}
if(m_semaphoreGetDescEvt.wait("retrieveDescriptors") != 0) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc != 0) {
return false;
}
@ -337,6 +338,22 @@ NimBLEUUID NimBLERemoteCharacteristic::getUUID() {
} // getUUID
/**
* @brief Get the value of the remote characteristic.
* @return The value of the remote characteristic.
*/
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
portENTER_CRITICAL(&m_valMux);
std::string value = m_value;
if(timestamp != nullptr) {
*timestamp = m_timestamp;
}
portEXIT_CRITICAL(&m_valMux);
return value;
}
/**
* @brief Read an unsigned 16 bit value
* @return The unsigned 16 bit value.
@ -384,33 +401,31 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
NIMBLE_LOGD(LOG_TAG, ">> readValue(): uuid: %s, handle: %d 0x%.2x",
getUUID().toString().c_str(), getHandle(), getHandle());
int rc = 0;
int retryCount = 1;
NimBLEClient* pClient = getRemoteService()->getClient();
std::string value;
// Check to see that we are connected.
if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected");
return "";
return value;
}
do {
m_semaphoreReadCharEvt.take("readValue");
// Clear the value before reading.
m_value = "";
int rc = 0;
int retryCount = 1;
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
do {
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteCharacteristic::onReadCB,
this);
&taskData);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read characteristic; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreReadCharEvt.give(0);
return "";
return value;
}
rc = m_semaphoreReadCharEvt.wait("readValue");
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = taskData.rc;
switch(rc){
case 0:
case BLE_HS_EDONE:
@ -428,39 +443,24 @@ std::string NimBLERemoteCharacteristic::readValue(time_t *timestamp) {
break;
/* Else falls through. */
default:
return "";
NIMBLE_LOGE(LOG_TAG, "<< readValue rc=%d", rc);
return value;
}
} while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< readValue(): length: %d", m_value.length());
m_semaphoreReadCharEvt.take("returnValue");
std::string value = m_value;
portENTER_CRITICAL(&m_valMux);
m_value = value;
m_timestamp = time(nullptr);
if(timestamp != nullptr) {
*timestamp = m_timestamp;
}
m_semaphoreReadCharEvt.give();
portEXIT_CRITICAL(&m_valMux);
NIMBLE_LOGD(LOG_TAG, "<< readValue length: %d rc=%d", value.length(), rc);
return value;
} // readValue
/**
* @brief Get the value of the remote characteristic.
* @return The value of the remote characteristic.
*/
std::string NimBLERemoteCharacteristic::getValue(time_t *timestamp) {
m_semaphoreReadCharEvt.take("getValue");
std::string value = m_value;
if(timestamp != nullptr) {
*timestamp = m_timestamp;
}
m_semaphoreReadCharEvt.give();
return value;
}
/**
* @brief Callback for characteristic read operation.
* @return 0 or error code.
@ -469,27 +469,35 @@ int NimBLERemoteCharacteristic::onReadCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
uint16_t conn_id = characteristic->getRemoteService()->getClient()->getConnId();
// Make sure the read is for this client
if(conn_id != conn_handle) {
return 0;
}
NIMBLE_LOGI(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
if(error->status == 0) {
if(attr) {
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
std::string *strBuf = (std::string*)pTaskData->buf;
int rc = error->status;
characteristic->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
characteristic->m_timestamp = time(nullptr);
if(rc == 0) {
if(attr) {
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} else {
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
return 0;
}
}
// Read complete release semaphore and let the app can continue.
characteristic->m_semaphoreReadCharEvt.give(error->status);
return 0;
}
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
return rc;
}
@ -509,7 +517,7 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, bool response, notify_c
return false;
}
m_notifyCallback = notifyCallback; // Save the notification callback.
m_notifyCallback = notifyCallback;
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
@ -572,7 +580,7 @@ bool NimBLERemoteCharacteristic::registerForNotify(notify_callback notifyCallbac
*/
void NimBLERemoteCharacteristic::deleteDescriptors() {
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptors");
// Iterate through all the descriptors releasing their storage and erasing them from the vector.
for(auto &it: m_descriptorVector) {
delete it;
}
@ -588,7 +596,7 @@ void NimBLERemoteCharacteristic::deleteDescriptors() {
*/
size_t NimBLERemoteCharacteristic::deleteDescriptor(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> deleteDescriptor");
// Delete the requested descriptor.
for(auto it = m_descriptorVector.begin(); it != m_descriptorVector.end(); ++it) {
if((*it)->getUUID() == uuid) {
delete *it;
@ -665,47 +673,45 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
NIMBLE_LOGD(LOG_TAG, ">> writeValue(), length: %d", length);
NimBLEClient* pClient = getRemoteService()->getClient();
int rc = 0;
int retryCount = 1;
uint16_t mtu;
// Check to see that we are connected.
if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected");
return false;
}
mtu = ble_att_mtu(pClient->getConnId()) - 3;
int rc = 0;
int retryCount = 1;
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
// Check if the data length is longer than we can write in 1 connection event.
// Check if the data length is longer than we can write in one connection event.
// If so we must do a long write which requires a response.
if(length <= mtu && !response) {
rc = ble_gattc_write_no_rsp_flat(pClient->getConnId(), m_handle, data, length);
return (rc==0);
}
do {
m_semaphoreWriteCharEvt.take("writeValue");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
do {
if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
NimBLERemoteCharacteristic::onWriteCB,
this);
&taskData);
} else {
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length,
NimBLERemoteCharacteristic::onWriteCB,
this);
&taskData);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write characteristic; rc=%d", rc);
m_semaphoreWriteCharEvt.give();
return false;
}
rc = m_semaphoreWriteCharEvt.wait("writeValue");
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = taskData.rc;
switch(rc){
case 0:
@ -725,11 +731,12 @@ bool NimBLERemoteCharacteristic::writeValue(const uint8_t* data, size_t length,
break;
/* Else falls through. */
default:
NIMBLE_LOGE(LOG_TAG, "<< writeValue, rc: %d", rc);
return false;
}
} while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d",rc);
NIMBLE_LOGD(LOG_TAG, "<< writeValue, rc: %d", rc);
return (rc == 0);
} // writeValue
@ -742,29 +749,21 @@ int NimBLERemoteCharacteristic::onWriteCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
NimBLERemoteCharacteristic* characteristic = (NimBLERemoteCharacteristic*)arg;
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
// Make sure the discovery is for this device
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0;
}
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
characteristic->m_semaphoreWriteCharEvt.give(error->status);
pTaskData->rc = error->status;
xTaskNotifyGive(pTaskData->task);
return 0;
}
void NimBLERemoteCharacteristic::releaseSemaphores() {
for (auto &it: m_descriptorVector) {
it->releaseSemaphores();
}
m_semaphoreWriteCharEvt.give(1);
m_semaphoreGetDescEvt.give(1);
m_semaphoreReadCharEvt.give(1);
}
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */

View file

@ -32,6 +32,12 @@ class NimBLERemoteDescriptor;
typedef void (*notify_callback)(NimBLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData, size_t length, bool isNotify);
typedef struct {
const NimBLEUUID *uuid;
void *task_data;
} desc_filter_t;
/**
* @brief A model of a remote %BLE characteristic.
*/
@ -110,7 +116,6 @@ private:
struct ble_gatt_attr *attr, void *arg);
static int onWriteCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
void releaseSemaphores();
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg);
@ -121,12 +126,10 @@ private:
uint16_t m_handle;
uint16_t m_defHandle;
NimBLERemoteService* m_pRemoteService;
FreeRTOS::Semaphore m_semaphoreGetDescEvt = FreeRTOS::Semaphore("GetDescEvt");
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt");
std::string m_value;
notify_callback m_notifyCallback;
time_t m_timestamp;
portMUX_TYPE m_valMux;
// We maintain a vector of descriptors owned by this characteristic.
std::vector<NimBLERemoteDescriptor*> m_descriptorVector;

View file

@ -45,9 +45,9 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo
m_uuid = nullptr;
break;
}
m_handle = dsc->handle;
m_pRemoteCharacteristic = pRemoteCharacteristic;
}
@ -78,96 +78,6 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() {
} // getUUID
/**
* @brief Callback for Descriptor read operation.
* @return 0 or error code.
*/
int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)arg;
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
// Make sure the discovery is for this device
if(conn_id != conn_handle){
return 0;
}
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
if(error->status == 0){
if(attr){
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
desc->m_value += std::string((char*) attr->om->om_data, attr->om->om_len);
return 0;
}
}
// Read complete release semaphore and let the app can continue.
desc->m_semaphoreReadDescrEvt.give(error->status);
return 0;
}
std::string NimBLERemoteDescriptor::readValue() {
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
int rc = 0;
int retryCount = 1;
// Clear the value before reading.
m_value = "";
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
// Check to see that we are connected.
if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected");
return "";
}
do {
m_semaphoreReadDescrEvt.take("ReadDescriptor");
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteDescriptor::onReadCB,
this);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreReadDescrEvt.give(0);
return "";
}
rc = m_semaphoreReadDescrEvt.wait("ReadDescriptor");
switch(rc){
case 0:
case BLE_HS_EDONE:
rc = 0;
break;
// Descriptor is not long-readable, return with what we have.
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
rc = 0;
break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
if (retryCount && pClient->secureConnection())
break;
/* Else falls through. */
default:
return "";
}
} while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d", m_value.length());
return m_value;
} // readValue
uint8_t NimBLERemoteDescriptor::readUInt8() {
std::string value = readValue();
if (value.length() >= 1) {
@ -195,6 +105,100 @@ uint32_t NimBLERemoteDescriptor::readUInt32() {
} // readUInt32
std::string NimBLERemoteDescriptor::readValue() {
NIMBLE_LOGD(LOG_TAG, ">> Descriptor readValue: %s", toString().c_str());
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
std::string value;
if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected");
return value;
}
int rc = 0;
int retryCount = 1;
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(),0, &value};
do {
rc = ble_gattc_read_long(pClient->getConnId(), m_handle, 0,
NimBLERemoteDescriptor::onReadCB,
&taskData);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to read descriptor; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc));
return value;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = taskData.rc;
switch(rc){
case 0:
case BLE_HS_EDONE:
rc = 0;
break;
// Descriptor is not long-readable, return with what we have.
case BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_LONG):
NIMBLE_LOGI(LOG_TAG, "Attribute not long");
rc = 0;
break;
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHEN):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_AUTHOR):
case BLE_HS_ATT_ERR(BLE_ATT_ERR_INSUFFICIENT_ENC):
if (retryCount && pClient->secureConnection())
break;
/* Else falls through. */
default:
return value;
}
} while(rc != 0 && retryCount--);
NIMBLE_LOGD(LOG_TAG, "<< Descriptor readValue(): length: %d rc=%d", value.length(), rc);
return value;
} // readValue
/**
* @brief Callback for Descriptor read operation.
* @return 0 or error code.
*/
int NimBLERemoteDescriptor::onReadCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteDescriptor* desc = (NimBLERemoteDescriptor*)pTaskData->pATT;
uint16_t conn_id = desc->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId();
if(conn_id != conn_handle){
return 0;
}
NIMBLE_LOGD(LOG_TAG, "Read complete; status=%d conn_handle=%d", error->status, conn_handle);
std::string *strBuf = (std::string*)pTaskData->buf;
int rc = error->status;
if(rc == 0) {
if(attr) {
if(((*strBuf).length() + attr->om->om_len) > BLE_ATT_ATTR_MAX_LEN) {
rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
} else {
NIMBLE_LOGD(LOG_TAG, "Got %d bytes", attr->om->om_len);
(*strBuf) += std::string((char*) attr->om->om_data, attr->om->om_len);
return 0;
}
}
}
pTaskData->rc = rc;
xTaskNotifyGive(pTaskData->task);
return rc;
}
/**
* @brief Return a string representation of this BLE Remote Descriptor.
* @retun A string representation of this BLE Remote Descriptor.
@ -218,16 +222,17 @@ int NimBLERemoteDescriptor::onWriteCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg)
{
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)arg;
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteDescriptor* descriptor = (NimBLERemoteDescriptor*)pTaskData->pATT;
// Make sure the discovery is for this device
if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0;
}
NIMBLE_LOGD(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
NIMBLE_LOGI(LOG_TAG, "Write complete; status=%d conn_handle=%d", error->status, conn_handle);
descriptor->m_semaphoreDescWrite.give(error->status);
pTaskData->rc = error->status;
xTaskNotifyGive(pTaskData->task);
return 0;
}
@ -245,17 +250,15 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
int rc = 0;
int retryCount = 1;
uint16_t mtu;
// Check to see that we are connected.
if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected");
return false;
}
mtu = ble_att_mtu(pClient->getConnId()) - 3;
int rc = 0;
int retryCount = 1;
uint16_t mtu = ble_att_mtu(pClient->getConnId()) - 3;
// Check if the data length is longer than we can write in 1 connection event.
// If so we must do a long write which requires a response.
@ -264,31 +267,31 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
return (rc == 0);
}
do {
m_semaphoreDescWrite.take("WriteDescriptor");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
do {
if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
NimBLERemoteDescriptor::onWriteCB,
this);
&taskData);
} else {
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length,
NimBLERemoteDescriptor::onWriteCB,
this);
&taskData);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
m_semaphoreDescWrite.give();
return false;
}
rc = m_semaphoreDescWrite.wait("WriteDescriptor");
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = taskData.rc;
switch(rc){
switch(rc) {
case 0:
case BLE_HS_EDONE:
rc = 0;
@ -335,13 +338,5 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
} // writeValue
/**
* @brief In the event of an error this is called to make sure we don't block.
*/
void NimBLERemoteDescriptor::releaseSemaphores() {
m_semaphoreDescWrite.give(1);
m_semaphoreReadDescrEvt.give(1);
}
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */

View file

@ -31,16 +31,24 @@ public:
uint16_t getHandle();
NimBLERemoteCharacteristic* getRemoteCharacteristic();
NimBLEUUID getUUID();
std::string readValue(void);
uint8_t readUInt8(void);
uint16_t readUInt16(void);
uint32_t readUInt32(void);
std::string readValue();
template<typename T>
T readValue(bool skipSizeCheck = false) {
std::string value = readValue();
if(!skipSizeCheck && value.size() < sizeof(T)) return T();
const char *pData = value.data();
return *((T *)pData);
}
uint8_t readUInt8() __attribute__ ((deprecated));
uint16_t readUInt16() __attribute__ ((deprecated));
uint32_t readUInt32() __attribute__ ((deprecated));
std::string toString(void);
bool writeValue(const uint8_t* data, size_t length, bool response = false);
bool writeValue(const std::string &newValue, bool response = false);
bool writeValue(uint8_t newValue, bool response = false);
private:
friend class NimBLERemoteCharacteristic;
@ -50,16 +58,10 @@ private:
struct ble_gatt_attr *attr, void *arg);
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg);
void releaseSemaphores();
uint16_t m_handle;
NimBLEUUID m_uuid;
std::string m_value;
NimBLERemoteCharacteristic* m_pRemoteCharacteristic;
FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt");
FreeRTOS::Semaphore m_semaphoreDescWrite = FreeRTOS::Semaphore("WriteDescEvt");
};
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)

View file

@ -148,43 +148,34 @@ int NimBLERemoteService::characteristicDiscCB(uint16_t conn_handle,
NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? chr->val_handle : -1);
NimBLERemoteService *service = (NimBLERemoteService*)arg;
int rc=0;
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT;
// Make sure the discovery is for this device
if(service->getClient()->getConnId() != conn_handle){
return 0;
}
switch (error->status) {
case 0: {
if(error->status == 0) {
// Found a service - add it to the vector
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
service->m_characteristicVector.push_back(pRemoteCharacteristic);
break;
return 0;
}
case BLE_HS_EDONE:{
/** All characteristics in this service discovered; start discovering
* characteristics in the next service.
*/
service->m_semaphoreGetCharEvt.give(0);
rc = 0;
break;
if(error->status == BLE_HS_EDONE) {
pTaskData->rc = 0;
} else {
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
error->status,
NimBLEUtils::returnCodeToString(error->status));
pTaskData->rc = error->status;
}
default:
rc = error->status;
break;
}
if (rc != 0) {
/* Error; abort discovery. */
// pass non-zero to semaphore on error to indicate an error finding characteristics
// release memory from any characteristics we created
//service->deleteCharacteristics(); --this will now be done when we clear services on returning with error
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
service->m_semaphoreGetCharEvt.give(1);
}
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered. status: %d", rc);
return rc;
xTaskNotifyGive(pTaskData->task);
NIMBLE_LOGD(LOG_TAG,"<< Characteristic Discovered");
return error->status;
}
@ -197,32 +188,31 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
int rc = 0;
//deleteCharacteristics(); // Forget any previous characteristics.
m_semaphoreGetCharEvt.take("retrieveCharacteristics");
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
m_startHandle,
m_endHandle,
NimBLERemoteService::characteristicDiscCB,
this);
&taskData);
} else {
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
m_startHandle,
m_endHandle,
&uuid_filter->getNative()->u,
NimBLERemoteService::characteristicDiscCB,
this);
&taskData);
}
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreGetCharEvt.give();
return false;
}
if(m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0){
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc == 0){
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
return true;
}
@ -319,7 +309,7 @@ void NimBLERemoteService::deleteCharacteristics() {
for(auto &it: m_characteristicVector) {
delete it;
}
m_characteristicVector.clear(); // Clear the vector
m_characteristicVector.clear();
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics");
} // deleteCharacteristics
@ -331,7 +321,7 @@ void NimBLERemoteService::deleteCharacteristics() {
*/
size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic");
// Delete the requested characteristic.
for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) {
if((*it)->getUUID() == uuid) {
delete *it;
@ -374,16 +364,5 @@ std::string NimBLERemoteService::toString() {
} // toString
/**
* @brief called when an error occurrs and we need to release the semaphores to resume operations.
* Will release all characteristic and subsequently all descriptor semaphores for this service.
*/
void NimBLERemoteService::releaseSemaphores() {
for(auto &it: m_characteristicVector) {
it->releaseSemaphores();
}
m_semaphoreGetCharEvt.give(1);
}
#endif // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */

View file

@ -22,7 +22,6 @@
#include "NimBLEClient.h"
#include "NimBLEUUID.h"
#include "FreeRTOS.h"
#include "NimBLERemoteCharacteristic.h"
#include <vector>
@ -79,7 +78,6 @@ private:
std::vector<NimBLERemoteCharacteristic*> m_characteristicVector;
NimBLEClient* m_pClient;
FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt");
NimBLEUUID m_uuid;
uint16_t m_startHandle;
uint16_t m_endHandle;

View file

@ -18,7 +18,6 @@
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEScan.h"
#include "NimBLEUtils.h"
#include "NimBLEDevice.h"
#include "NimBLELog.h"
@ -70,6 +69,7 @@ NimBLEScan::NimBLEScan() {
m_pAdvertisedDeviceCallbacks = nullptr;
m_stopped = true;
m_wantDuplicates = false;
m_pTaskData = nullptr;
}
@ -101,14 +101,6 @@ NimBLEScan::NimBLEScan() {
NimBLEAddress advertisedAddress(event->disc.addr);
// Print advertisement data
// print_adv_fields(&fields);
// If we are not scanning, nothing to do with the extra results.
if (pScan->m_stopped) {
return 0;
}
// Examine our list of ignored addresses and stop processing if we don't want to see it or are already connected
if(NimBLEDevice::isIgnored(advertisedAddress)) {
NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
@ -131,7 +123,6 @@ NimBLEScan::NimBLEScan() {
advertisedDevice = new NimBLEAdvertisedDevice();
advertisedDevice->setAddressType(event->disc.addr.type);
advertisedDevice->setAddress(advertisedAddress);
//NIMBLE_LOGE(LOG_TAG, "advertisement type: %d, %s",event->disc.event_type, NimBLEUtils::advTypeToString(event->disc.event_type));
advertisedDevice->setAdvType(event->disc.event_type);
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str());
@ -153,7 +144,6 @@ NimBLEScan::NimBLEScan() {
} else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
}
//m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
}
return 0;
@ -167,7 +157,11 @@ NimBLEScan::NimBLEScan() {
}
pScan->m_stopped = true;
pScan->m_semaphoreScanEnd.give();
if(pScan->m_pTaskData != nullptr) {
pScan->m_pTaskData->rc = event->disc_complete.reason;
xTaskNotifyGive(pScan->m_pTaskData->task);
}
return 0;
}
@ -249,7 +243,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
}
m_stopped = false;
m_semaphoreScanEnd.take("start");
// Save the callback to be invoked when the scan completes.
m_scanCompleteCB = scanCompleteCB;
@ -275,7 +268,7 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
NimBLEScan::handleGapEvent, this);
if(rc == BLE_HS_EBUSY) {
vTaskDelay(2);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
} while(rc == BLE_HS_EBUSY);
@ -283,7 +276,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc));
m_stopped = true;
m_semaphoreScanEnd.give();
return false;
}
@ -298,9 +290,18 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
* @return The BLEScanResults.
*/
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
if(start(duration, nullptr, is_continue)) {
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release.
if(duration == 0) {
NIMBLE_LOGW(LOG_TAG, "Blocking scan called with duration = forever");
}
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
m_pTaskData = &taskData;
if(start(duration, nullptr, is_continue)) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
m_pTaskData = nullptr;
return m_scanResults;
} // start
@ -309,13 +310,13 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
* @brief Stop an in progress scan.
* @return N/A.
*/
void NimBLEScan::stop() {
bool NimBLEScan::stop() {
NIMBLE_LOGD(LOG_TAG, ">> stop()");
int rc = ble_gap_disc_cancel();
if (rc != 0 && rc != BLE_HS_EALREADY) {
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
return;
return false;
}
m_stopped = true;
@ -324,9 +325,12 @@ void NimBLEScan::stop() {
m_scanCompleteCB(m_scanResults);
}
m_semaphoreScanEnd.give();
if(m_pTaskData != nullptr) {
xTaskNotifyGive(m_pTaskData->task);
}
NIMBLE_LOGD(LOG_TAG, "<< stop()");
return true;
} // stop
@ -350,7 +354,6 @@ void NimBLEScan::erase(const NimBLEAddress &address) {
*/
void NimBLEScan::onHostReset() {
m_stopped = true;
m_semaphoreScanEnd.give();
}

View file

@ -20,7 +20,7 @@
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEAdvertisedDevice.h"
#include "FreeRTOS.h"
#include "NimBLEUtils.h"
#include "host/ble_gap.h"
@ -66,7 +66,7 @@ public:
void setActiveScan(bool active);
void setInterval(uint16_t intervalMSecs);
void setWindow(uint16_t windowMSecs);
void stop();
bool stop();
void clearResults();
NimBLEScanResults getResults();
void erase(const NimBLEAddress &address);
@ -85,8 +85,8 @@ private:
bool m_stopped;
bool m_wantDuplicates;
NimBLEScanResults m_scanResults;
FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd");
uint32_t m_duration;
ble_task_data_t *m_pTaskData;
};
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)

View file

@ -502,8 +502,13 @@ void print_bytes(const uint8_t *bytes, int len)
int i;
for (i = 0; i < len; i++) {
MODLOG_DFLT(DEBUG, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
MODLOG_DFLT(ERROR, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
if(i % 30 == 0){
MODLOG_DFLT(ERROR, "\n");
}
}
MODLOG_DFLT(ERROR, "\n");
}
void print_mbuf(const struct os_mbuf *om)