Remove task notification for server indications.

This resolves an issue when sending an indication from a callback that can cause the server to hang.
This commit is contained in:
h2zero 2021-05-17 14:08:02 -06:00
parent e45fb8616a
commit b62358a520
4 changed files with 72 additions and 47 deletions

View file

@ -52,7 +52,6 @@ NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t prop
m_pService = pService; m_pService = pService;
m_value = ""; m_value = "";
m_valMux = portMUX_INITIALIZER_UNLOCKED; m_valMux = portMUX_INITIALIZER_UNLOCKED;
m_pTaskData = nullptr;
m_timestamp = 0; m_timestamp = 0;
} // NimBLECharacteristic } // NimBLECharacteristic
@ -301,14 +300,12 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
subVal |= NIMBLE_SUB_INDICATE; subVal |= NIMBLE_SUB_INDICATE;
} }
if(m_pTaskData != nullptr) {
m_pTaskData->rc = (subVal & NIMBLE_SUB_INDICATE) ? 0 :
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED;
xTaskNotifyGive(m_pTaskData->task);
}
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d", NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
event->subscribe.conn_handle, subVal); event->subscribe.conn_handle, subVal);
if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
}
m_pCallbacks->onSubscribe(this, &desc, subVal); m_pCallbacks->onSubscribe(this, &desc, subVal);
@ -329,9 +326,7 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
} else if(it != m_subscribedVec.end()) { } else if(it != m_subscribedVec.end()) {
m_subscribedVec.erase(it); m_subscribedVec.erase(it);
m_subscribedVec.shrink_to_fit();
} }
} }
@ -416,40 +411,20 @@ void NimBLECharacteristic::notify(bool is_notification) {
// We also must create it in each loop iteration because it is consumed with each host call. // We also must create it in each loop iteration because it is consumed with each host call.
os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length); os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
NimBLECharacteristicCallbacks::Status statusRC;
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) { if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr}; if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
m_pTaskData = &taskData; NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
os_mbuf_free_chain(om);
return;
}
rc = ble_gattc_indicate_custom(it.first, m_handle, om); rc = ble_gattc_indicate_custom(it.first, m_handle, om);
if(rc != 0){ if(rc != 0){
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT; NimBLEDevice::getServer()->clearIndicateWait(it.first);
} else {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = m_pTaskData->rc;
}
m_pTaskData = nullptr;
if(rc == BLE_HS_EDONE) {
rc = 0;
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
} else if(rc == BLE_HS_ETIMEOUT) {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
} }
} else { } else {
rc = ble_gattc_notify_custom(it.first, m_handle, om); ble_gattc_notify_custom(it.first, m_handle, om);
if(rc == 0) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
}
} }
m_pCallbacks->onStatus(this, statusRC, rc);
} }
NIMBLE_LOGD(LOG_TAG, "<< notify"); NIMBLE_LOGD(LOG_TAG, "<< notify");

View file

@ -150,7 +150,6 @@ private:
NimBLEService* m_pService; NimBLEService* m_pService;
std::string m_value; std::string m_value;
std::vector<NimBLEDescriptor*> m_dscVec; std::vector<NimBLEDescriptor*> m_dscVec;
ble_task_data_t *m_pTaskData;
portMUX_TYPE m_valMux; portMUX_TYPE m_valMux;
time_t m_timestamp; time_t m_timestamp;

View file

@ -37,6 +37,7 @@ static NimBLEServerCallbacks defaultCallbacks;
* the NimBLEDevice class. * the NimBLEDevice class.
*/ */
NimBLEServer::NimBLEServer() { NimBLEServer::NimBLEServer() {
memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
// m_svcChgChrHdl = 0xffff; // Future Use // m_svcChgChrHdl = 0xffff; // Future Use
m_pServerCallbacks = &defaultCallbacks; m_pServerCallbacks = &defaultCallbacks;
m_gattsStarted = false; m_gattsStarted = false;
@ -419,18 +420,44 @@ NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
} // BLE_GAP_EVENT_MTU } // BLE_GAP_EVENT_MTU
case BLE_GAP_EVENT_NOTIFY_TX: { case BLE_GAP_EVENT_NOTIFY_TX: {
if(event->notify_tx.indication && event->notify_tx.status != 0) { NimBLECharacteristic *pChar = nullptr;
for(auto &it : server->m_notifyChrVec) {
if(it->getHandle() == event->notify_tx.attr_handle) { for(auto &it : server->m_notifyChrVec) {
if(it->m_pTaskData != nullptr) { if(it->getHandle() == event->notify_tx.attr_handle) {
it->m_pTaskData->rc = event->notify_tx.status; pChar = it;
xTaskNotifyGive(it->m_pTaskData->task);
}
break;
}
} }
} }
if(pChar == nullptr) {
return 0;
}
NimBLECharacteristicCallbacks::Status statusRC;
if(event->notify_tx.indication) {
if(event->notify_tx.status != 0) {
if(event->notify_tx.status == BLE_HS_EDONE) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
} else if(rc == BLE_HS_ETIMEOUT) {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
}
} else {
return 0;
}
server->clearIndicateWait(event->notify_tx.conn_handle);
} else {
if(event->notify_tx.status == 0) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
}
}
pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status);
return 0; return 0;
} // BLE_GAP_EVENT_NOTIFY_TX } // BLE_GAP_EVENT_NOTIFY_TX
@ -732,6 +759,27 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle,
}// updateConnParams }// updateConnParams
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
return false;
}
}
return true;
}
void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
return;
}
}
}
/** Default callback handlers */ /** Default callback handlers */
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) { void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {

View file

@ -77,6 +77,7 @@ private:
bool m_svcChanged; bool m_svcChanged;
NimBLEServerCallbacks* m_pServerCallbacks; NimBLEServerCallbacks* m_pServerCallbacks;
bool m_deleteCallbacks; bool m_deleteCallbacks;
uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
std::vector<uint16_t> m_connectedPeersVec; std::vector<uint16_t> m_connectedPeersVec;
// uint16_t m_svcChgChrHdl; // Future use // uint16_t m_svcChgChrHdl; // Future use
@ -86,6 +87,8 @@ private:
static int handleGapEvent(struct ble_gap_event *event, void *arg); static int handleGapEvent(struct ble_gap_event *event, void *arg);
void resetGATT(); void resetGATT();
bool setIndicateWait(uint16_t conn_handle);
void clearIndicateWait(uint16_t conn_handle);
}; // NimBLEServer }; // NimBLEServer