mirror of
https://github.com/h2zero/esp-nimble-cpp.git
synced 2024-11-22 05:00:55 +01:00
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:
parent
e45fb8616a
commit
b62358a520
4 changed files with 72 additions and 47 deletions
|
@ -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,15 +300,13 @@ 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);
|
||||||
|
|
||||||
auto it = m_subscribedVec.begin();
|
auto it = m_subscribedVec.begin();
|
||||||
|
@ -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,42 +411,22 @@ 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");
|
||||||
} // Notify
|
} // Notify
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
for(auto &it : server->m_notifyChrVec) {
|
||||||
if(it->getHandle() == event->notify_tx.attr_handle) {
|
if(it->getHandle() == event->notify_tx.attr_handle) {
|
||||||
if(it->m_pTaskData != nullptr) {
|
pChar = it;
|
||||||
it->m_pTaskData->rc = event->notify_tx.status;
|
|
||||||
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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue