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

View file

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

View file

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

View file

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

View file

@ -45,9 +45,9 @@ NimBLERemoteDescriptor::NimBLERemoteDescriptor(NimBLERemoteCharacteristic* pRemo
m_uuid = nullptr; m_uuid = nullptr;
break; break;
} }
m_handle = dsc->handle; m_handle = dsc->handle;
m_pRemoteCharacteristic = pRemoteCharacteristic; m_pRemoteCharacteristic = pRemoteCharacteristic;
} }
@ -78,96 +78,6 @@ NimBLEUUID NimBLERemoteDescriptor::getUUID() {
} // 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() { uint8_t NimBLERemoteDescriptor::readUInt8() {
std::string value = readValue(); std::string value = readValue();
if (value.length() >= 1) { if (value.length() >= 1) {
@ -195,6 +105,100 @@ uint32_t NimBLERemoteDescriptor::readUInt32() {
} // 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. * @brief Return a string representation of this BLE Remote Descriptor.
* @retun 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, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg) 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){ if(descriptor->getRemoteCharacteristic()->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0; 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; return 0;
} }
@ -245,17 +250,15 @@ bool NimBLERemoteDescriptor::writeValue(const uint8_t* data, size_t length, bool
NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient(); NimBLEClient* pClient = getRemoteCharacteristic()->getRemoteService()->getClient();
int rc = 0;
int retryCount = 1;
uint16_t mtu;
// Check to see that we are connected. // Check to see that we are connected.
if (!pClient->isConnected()) { if (!pClient->isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Disconnected"); NIMBLE_LOGE(LOG_TAG, "Disconnected");
return false; 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 1 connection event.
// If so we must do a long write which requires a response. // 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); return (rc == 0);
} }
do { ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
m_semaphoreDescWrite.take("WriteDescriptor");
do {
if(length > mtu) { if(length > mtu) {
NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length); NIMBLE_LOGI(LOG_TAG,"long write %d bytes", length);
os_mbuf *om = ble_hs_mbuf_from_flat(data, length); os_mbuf *om = ble_hs_mbuf_from_flat(data, length);
rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om, rc = ble_gattc_write_long(pClient->getConnId(), m_handle, 0, om,
NimBLERemoteDescriptor::onWriteCB, NimBLERemoteDescriptor::onWriteCB,
this); &taskData);
} else { } else {
rc = ble_gattc_write_flat(pClient->getConnId(), m_handle, rc = ble_gattc_write_flat(pClient->getConnId(), m_handle,
data, length, data, length,
NimBLERemoteDescriptor::onWriteCB, NimBLERemoteDescriptor::onWriteCB,
this); &taskData);
} }
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc); NIMBLE_LOGE(LOG_TAG, "Error: Failed to write descriptor; rc=%d", rc);
m_semaphoreDescWrite.give();
return false; return false;
} }
rc = m_semaphoreDescWrite.wait("WriteDescriptor"); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = taskData.rc;
switch(rc){ switch(rc) {
case 0: case 0:
case BLE_HS_EDONE: case BLE_HS_EDONE:
rc = 0; rc = 0;
@ -335,13 +338,5 @@ bool NimBLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
} // writeValue } // 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 // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View file

@ -31,16 +31,24 @@ public:
uint16_t getHandle(); uint16_t getHandle();
NimBLERemoteCharacteristic* getRemoteCharacteristic(); NimBLERemoteCharacteristic* getRemoteCharacteristic();
NimBLEUUID getUUID(); NimBLEUUID getUUID();
std::string readValue(void); std::string readValue();
uint8_t readUInt8(void);
uint16_t readUInt16(void); template<typename T>
uint32_t readUInt32(void); 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); std::string toString(void);
bool writeValue(const uint8_t* data, size_t length, bool response = false); bool writeValue(const uint8_t* data, size_t length, bool response = false);
bool writeValue(const std::string &newValue, bool response = false); bool writeValue(const std::string &newValue, bool response = false);
bool writeValue(uint8_t newValue, bool response = false); bool writeValue(uint8_t newValue, bool response = false);
private: private:
friend class NimBLERemoteCharacteristic; friend class NimBLERemoteCharacteristic;
@ -50,16 +58,10 @@ private:
struct ble_gatt_attr *attr, void *arg); struct ble_gatt_attr *attr, void *arg);
static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error, static int onReadCB(uint16_t conn_handle, const struct ble_gatt_error *error,
struct ble_gatt_attr *attr, void *arg); struct ble_gatt_attr *attr, void *arg);
void releaseSemaphores();
uint16_t m_handle; uint16_t m_handle;
NimBLEUUID m_uuid; NimBLEUUID m_uuid;
std::string m_value;
NimBLERemoteCharacteristic* m_pRemoteCharacteristic; 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) #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", NIMBLE_LOGD(LOG_TAG,"Characteristic Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? chr->val_handle : -1); error->status, (error->status == 0) ? chr->val_handle : -1);
NimBLERemoteService *service = (NimBLERemoteService*)arg; ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
int rc=0; NimBLERemoteService *service = (NimBLERemoteService*)pTaskData->pATT;
// Make sure the discovery is for this device // Make sure the discovery is for this device
if(service->getClient()->getConnId() != conn_handle){ if(service->getClient()->getConnId() != conn_handle){
return 0; return 0;
} }
switch (error->status) { if(error->status == 0) {
case 0: { // Found a service - add it to the vector
// Found a service - add it to the vector NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr);
NimBLERemoteCharacteristic* pRemoteCharacteristic = new NimBLERemoteCharacteristic(service, chr); service->m_characteristicVector.push_back(pRemoteCharacteristic);
service->m_characteristicVector.push_back(pRemoteCharacteristic); return 0;
break;
}
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;
}
default:
rc = error->status;
break;
} }
if (rc != 0) {
/* Error; abort discovery. */ if(error->status == BLE_HS_EDONE) {
// pass non-zero to semaphore on error to indicate an error finding characteristics pTaskData->rc = 0;
// release memory from any characteristics we created } else {
//service->deleteCharacteristics(); --this will now be done when we clear services on returning with error NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s",
NIMBLE_LOGE(LOG_TAG, "characteristicDiscCB() rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); error->status,
service->m_semaphoreGetCharEvt.give(1); NimBLEUtils::returnCodeToString(error->status));
pTaskData->rc = error->status;
} }
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()); NIMBLE_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str());
int rc = 0; int rc = 0;
//deleteCharacteristics(); // Forget any previous characteristics. ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
m_semaphoreGetCharEvt.take("retrieveCharacteristics");
if(uuid_filter == nullptr) { if(uuid_filter == nullptr) {
rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(), rc = ble_gattc_disc_all_chrs(m_pClient->getConnId(),
m_startHandle, m_startHandle,
m_endHandle, m_endHandle,
NimBLERemoteService::characteristicDiscCB, NimBLERemoteService::characteristicDiscCB,
this); &taskData);
} else { } else {
rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(), rc = ble_gattc_disc_chrs_by_uuid(m_pClient->getConnId(),
m_startHandle, m_startHandle,
m_endHandle, m_endHandle,
&uuid_filter->getNative()->u, &uuid_filter->getNative()->u,
NimBLERemoteService::characteristicDiscCB, NimBLERemoteService::characteristicDiscCB,
this); &taskData);
} }
if (rc != 0) { if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc)); NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
m_semaphoreGetCharEvt.give();
return false; return false;
} }
if(m_semaphoreGetCharEvt.wait("retrieveCharacteristics") == 0){ ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc == 0){
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
return true; return true;
} }
@ -319,7 +309,7 @@ void NimBLERemoteService::deleteCharacteristics() {
for(auto &it: m_characteristicVector) { for(auto &it: m_characteristicVector) {
delete it; delete it;
} }
m_characteristicVector.clear(); // Clear the vector m_characteristicVector.clear();
NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics"); NIMBLE_LOGD(LOG_TAG, "<< deleteCharacteristics");
} // deleteCharacteristics } // deleteCharacteristics
@ -331,7 +321,7 @@ void NimBLERemoteService::deleteCharacteristics() {
*/ */
size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) { size_t NimBLERemoteService::deleteCharacteristic(const NimBLEUUID &uuid) {
NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic"); NIMBLE_LOGD(LOG_TAG, ">> deleteCharacteristic");
// Delete the requested characteristic.
for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) { for(auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it) {
if((*it)->getUUID() == uuid) { if((*it)->getUUID() == uuid) {
delete *it; delete *it;
@ -374,16 +364,5 @@ std::string NimBLERemoteService::toString() {
} // 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 // #if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
#endif /* CONFIG_BT_ENABLED */ #endif /* CONFIG_BT_ENABLED */

View file

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

View file

@ -18,7 +18,6 @@
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER) #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
#include "NimBLEScan.h" #include "NimBLEScan.h"
#include "NimBLEUtils.h"
#include "NimBLEDevice.h" #include "NimBLEDevice.h"
#include "NimBLELog.h" #include "NimBLELog.h"
@ -70,6 +69,7 @@ NimBLEScan::NimBLEScan() {
m_pAdvertisedDeviceCallbacks = nullptr; m_pAdvertisedDeviceCallbacks = nullptr;
m_stopped = true; m_stopped = true;
m_wantDuplicates = false; m_wantDuplicates = false;
m_pTaskData = nullptr;
} }
@ -101,14 +101,6 @@ NimBLEScan::NimBLEScan() {
NimBLEAddress advertisedAddress(event->disc.addr); 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 // 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)) { if(NimBLEDevice::isIgnored(advertisedAddress)) {
NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str()); NIMBLE_LOGI(LOG_TAG, "Ignoring device: address: %s", advertisedAddress.toString().c_str());
@ -131,7 +123,6 @@ NimBLEScan::NimBLEScan() {
advertisedDevice = new NimBLEAdvertisedDevice(); advertisedDevice = new NimBLEAdvertisedDevice();
advertisedDevice->setAddressType(event->disc.addr.type); advertisedDevice->setAddressType(event->disc.addr.type);
advertisedDevice->setAddress(advertisedAddress); 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); advertisedDevice->setAdvType(event->disc.event_type);
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice); pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str()); 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) { } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
} }
//m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
} }
return 0; return 0;
@ -167,7 +157,11 @@ NimBLEScan::NimBLEScan() {
} }
pScan->m_stopped = true; 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; return 0;
} }
@ -249,7 +243,6 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
} }
m_stopped = false; m_stopped = false;
m_semaphoreScanEnd.take("start");
// Save the callback to be invoked when the scan completes. // Save the callback to be invoked when the scan completes.
m_scanCompleteCB = scanCompleteCB; 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, rc = ble_gap_disc(m_own_addr_type, duration, &m_scan_params,
NimBLEScan::handleGapEvent, this); NimBLEScan::handleGapEvent, this);
if(rc == BLE_HS_EBUSY) { if(rc == BLE_HS_EBUSY) {
vTaskDelay(2); vTaskDelay(1 / portTICK_PERIOD_MS);
} }
} while(rc == BLE_HS_EBUSY); } 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", NIMBLE_LOGE(LOG_TAG, "Error initiating GAP discovery procedure; rc=%d, %s",
rc, NimBLEUtils::returnCodeToString(rc)); rc, NimBLEUtils::returnCodeToString(rc));
m_stopped = true; m_stopped = true;
m_semaphoreScanEnd.give();
return false; return false;
} }
@ -298,9 +290,18 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
* @return The BLEScanResults. * @return The BLEScanResults.
*/ */
NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) { NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
if(start(duration, nullptr, is_continue)) { if(duration == 0) {
m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. 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; return m_scanResults;
} // start } // start
@ -309,13 +310,13 @@ NimBLEScanResults NimBLEScan::start(uint32_t duration, bool is_continue) {
* @brief Stop an in progress scan. * @brief Stop an in progress scan.
* @return N/A. * @return N/A.
*/ */
void NimBLEScan::stop() { bool NimBLEScan::stop() {
NIMBLE_LOGD(LOG_TAG, ">> stop()"); NIMBLE_LOGD(LOG_TAG, ">> stop()");
int rc = ble_gap_disc_cancel(); int rc = ble_gap_disc_cancel();
if (rc != 0 && rc != BLE_HS_EALREADY) { if (rc != 0 && rc != BLE_HS_EALREADY) {
NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc); NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
return; return false;
} }
m_stopped = true; m_stopped = true;
@ -324,9 +325,12 @@ void NimBLEScan::stop() {
m_scanCompleteCB(m_scanResults); m_scanCompleteCB(m_scanResults);
} }
m_semaphoreScanEnd.give(); if(m_pTaskData != nullptr) {
xTaskNotifyGive(m_pTaskData->task);
}
NIMBLE_LOGD(LOG_TAG, "<< stop()"); NIMBLE_LOGD(LOG_TAG, "<< stop()");
return true;
} // stop } // stop
@ -350,7 +354,6 @@ void NimBLEScan::erase(const NimBLEAddress &address) {
*/ */
void NimBLEScan::onHostReset() { void NimBLEScan::onHostReset() {
m_stopped = true; m_stopped = true;
m_semaphoreScanEnd.give();
} }

View file

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