@@ -98,6 +98,7 @@ BLEClient::BLEClient() {
|
98 | 98 | m_connectTimeout = 30000;
|
99 | 99 | m_pTaskData = nullptr;
|
100 | 100 | m_lastErr = 0;
|
| 101 | +m_terminateFailCount = 0; |
101 | 102 |
|
102 | 103 | m_pConnParams.scan_itvl = 16; // Scan interval in 0.625ms units (NimBLE Default)
|
103 | 104 | m_pConnParams.scan_window = 16; // Scan window in 0.625ms units (NimBLE Default)
|
@@ -107,9 +108,6 @@ BLEClient::BLEClient() {
|
107 | 108 | m_pConnParams.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT; // timeout = 400*10ms = 4000ms
|
108 | 109 | m_pConnParams.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; // Minimum length of connection event in 0.625ms units
|
109 | 110 | m_pConnParams.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; // Maximum length of connection event in 0.625ms units
|
110 |
| - |
111 |
| -memset(&m_dcTimer, 0, sizeof(m_dcTimer)); |
112 |
| -ble_npl_callout_init(&m_dcTimer, nimble_port_get_dflt_eventq(), BLEClient::dcTimerCb, this); |
113 | 111 | #endif
|
114 | 112 | } // BLEClient
|
115 | 113 |
|
@@ -124,10 +122,6 @@ BLEClient::~BLEClient() {
|
124 | 122 | }
|
125 | 123 | m_servicesMap.clear();
|
126 | 124 | m_servicesMapByInstID.clear();
|
127 |
| - |
128 |
| -#if defined(CONFIG_NIMBLE_ENABLED) |
129 |
| -ble_npl_callout_deinit(&m_dcTimer); |
130 |
| -#endif |
131 | 125 | } // ~BLEClient
|
132 | 126 |
|
133 | 127 | /**
|
@@ -186,34 +180,27 @@ bool BLEClient::secureConnection() {
|
186 | 180 | #endif
|
187 | 181 |
|
188 | 182 | #if defined(CONFIG_NIMBLE_ENABLED)
|
189 |
| -TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); |
190 |
| -ble_task_data_t taskData = {this, cur_task, 0, nullptr}; |
191 |
| - |
192 | 183 | int retryCount = 1;
|
| 184 | +BLETaskData taskData(const_cast<BLEClient*>(this), BLE_HS_ENOTCONN); |
| 185 | +m_pTaskData = &taskData; |
193 | 186 |
|
194 | 187 | do {
|
195 |
| -m_pTaskData = &taskData; |
196 |
| - |
197 |
| -int rc = BLESecurity::startSecurity(m_conn_id); |
198 |
| -if (rc != 0) { |
199 |
| -m_lastErr = rc; |
200 |
| -m_pTaskData = nullptr; |
201 |
| -return false; |
| 188 | +if (BLESecurity::startSecurity(m_conn_id)) { |
| 189 | +BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); |
202 | 190 | }
|
203 | 191 |
|
204 |
| -#ifdef ulTaskNotifyValueClear |
205 |
| -// Clear the task notification value to ensure we block |
206 |
| -ulTaskNotifyValueClear(cur_task, ULONG_MAX); |
207 |
| -#endif |
208 |
| -ulTaskNotifyTake(pdTRUE, portMAX_DELAY); |
209 |
| -} while (taskData.rc == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); |
| 192 | +} while (taskData.m_flags == (BLE_HS_ERR_HCI_BASE + BLE_ERR_PINKEY_MISSING) && retryCount--); |
210 | 193 |
|
211 |
| -if (taskData.rc != 0) { |
212 |
| -m_lastErr = taskData.rc; |
213 |
| -return false; |
| 194 | +m_pTaskData = nullptr; |
| 195 | + |
| 196 | +if (taskData.m_flags == 0) { |
| 197 | +log_d("<< secureConnection: success"); |
| 198 | +return true; |
214 | 199 | }
|
215 | 200 |
|
216 |
| -return true; |
| 201 | +m_lastErr = taskData.m_flags; |
| 202 | +log_e("secureConnection: failed rc=%d", taskData.m_flags); |
| 203 | +return false; |
217 | 204 | #endif
|
218 | 205 | } // secureConnection
|
219 | 206 |
|
@@ -376,7 +363,7 @@ bool BLEClient::setMTU(uint16_t mtu) {
|
376 | 363 | #endif
|
377 | 364 |
|
378 | 365 | #if defined(CONFIG_NIMBLE_ENABLED)
|
379 |
| -err = ble_gattc_exchange_mtu(m_conn_id, nullptr, nullptr); |
| 366 | +//err = ble_gattc_exchange_mtu(m_conn_id, nullptr, nullptr); |
380 | 367 | #endif
|
381 | 368 |
|
382 | 369 | if (err != ESP_OK) {
|
@@ -799,9 +786,6 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
|
799 | 786 | m_appId = BLEDevice::m_appId++;
|
800 | 787 | m_peerAddress = address;
|
801 | 788 |
|
802 |
| -TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); |
803 |
| -ble_task_data_t taskData = {this, cur_task, 0, nullptr}; |
804 |
| -m_pTaskData = &taskData; |
805 | 789 | int rc = 0;
|
806 | 790 |
|
807 | 791 | /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
|
@@ -837,45 +821,34 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
|
837 | 821 |
|
838 | 822 | } while (rc == BLE_HS_EBUSY);
|
839 | 823 |
|
840 |
| -m_lastErr = rc; |
841 |
| - |
842 | 824 | if (rc != 0) {
|
843 |
| -m_pTaskData = nullptr; |
| 825 | +m_lastErr = rc; |
844 | 826 | return false;
|
845 | 827 | }
|
846 | 828 |
|
847 |
| -#ifdef ulTaskNotifyValueClear |
848 |
| -// Clear the task notification value to ensure we block |
849 |
| -ulTaskNotifyValueClear(cur_task, ULONG_MAX); |
850 |
| -#endif |
| 829 | +BLETaskData taskData(this); |
| 830 | +m_pTaskData = &taskData; |
851 | 831 |
|
852 | 832 | // Wait for the connect timeout time +1 second for the connection to complete
|
853 |
| -if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(m_connectTimeout + 1000)) == pdFALSE) { |
854 |
| -m_pTaskData = nullptr; |
855 |
| -// If a connection was made but no response from MTU exchange; disconnect |
| 833 | +if (!BLEUtils::taskWait(taskData, m_connectTimeout + 1000)) { |
| 834 | +// If a connection was made but no response from MTU exchange proceed anyway |
856 | 835 | if (isConnected()) {
|
857 |
| -log_e("Connect timeout - no response"); |
858 |
| -disconnect(); |
| 836 | +taskData.m_flags = 0; |
859 | 837 | } else {
|
860 |
| -// workaround; if the controller doesn't cancel the connection |
861 |
| -// at the timeout, cancel it here. |
862 |
| -log_e("Connect timeout - canceling"); |
| 838 | +// workaround; if the controller doesn't cancel the connection at the timeout, cancel it here. |
| 839 | +log_e("Connect timeout - cancelling"); |
863 | 840 | ble_gap_conn_cancel();
|
| 841 | +taskData.m_flags = BLE_HS_ETIMEOUT; |
864 | 842 | }
|
| 843 | +} |
865 | 844 |
|
866 |
| -return false; |
| 845 | +m_pTaskData = nullptr; |
| 846 | +rc = taskData.m_flags; |
867 | 847 |
|
868 |
| -} else if (taskData.rc != 0) { |
869 |
| -m_lastErr = taskData.rc; |
870 |
| -log_e("Connection failed; status=%d %s", taskData.rc, BLEUtils::returnCodeToString(taskData.rc)); |
871 |
| -// If the failure was not a result of a disconnection |
872 |
| -// make sure we disconnect now to avoid dangling connections |
873 |
| -if (isConnected()) { |
874 |
| -disconnect(); |
875 |
| -} |
| 848 | +if (rc != 0) { |
| 849 | +log_e("Connection failed; status=%d %s", rc, BLEUtils::returnCodeToString(rc)); |
| 850 | +m_lastErr = rc; |
876 | 851 | return false;
|
877 |
| -} else { |
878 |
| -log_i("Connection established"); |
879 | 852 | }
|
880 | 853 |
|
881 | 854 | m_isConnected = true;
|
@@ -895,15 +868,16 @@ bool BLEClient::connect(BLEAddress address, uint8_t type, uint32_t timeoutMs) {
|
895 | 868 | */
|
896 | 869 | int BLEClient::serviceDiscoveredCB(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg)
|
897 | 870 | {
|
898 |
| -if (error == nullptr || service == nullptr) { |
899 |
| -log_e("serviceDiscoveredCB: error or service is nullptr"); |
900 |
| -return 0; |
901 |
| -} |
902 |
| - |
903 | 871 | log_d("Service Discovered >> status: %d handle: %d", error->status, (error->status == 0) ? service->start_handle : -1);
|
904 | 872 |
|
905 |
| -ble_task_data_t *pTaskData = (ble_task_data_t*)arg; |
906 |
| -BLEClient *client = (BLEClient*)pTaskData->pATT; |
| 873 | +BLETaskData *pTaskData = (BLETaskData*)arg; |
| 874 | +BLEClient *client = (BLEClient*)pTaskData->m_pInstance; |
| 875 | + |
| 876 | +if (error->status == BLE_HS_ENOTCONN) { |
| 877 | +log_e("<< Service Discovered; Disconnected"); |
| 878 | +BLEUtils::taskRelease(*pTaskData, error->status); |
| 879 | +return error->status; |
| 880 | +} |
907 | 881 |
|
908 | 882 | // Make sure the service discovery is for this device
|
909 | 883 | if(client->getConnId() != conn_handle){
|
@@ -918,53 +892,50 @@ int BLEClient::serviceDiscoveredCB(uint16_t conn_handle, const struct ble_gatt_e
|
918 | 892 | return 0;
|
919 | 893 | }
|
920 | 894 |
|
921 |
| -if(error->status == BLE_HS_EDONE) { |
922 |
| -pTaskData->rc = 0; |
923 |
| -} else { |
924 |
| -log_e("serviceDiscoveredCB() rc=%d %s", error->status, BLEUtils::returnCodeToString(error->status)); |
925 |
| -pTaskData->rc = error->status; |
926 |
| -} |
927 |
| - |
928 |
| -xTaskNotifyGive(pTaskData->task); |
929 |
| - |
| 895 | +BLEUtils::taskRelease(*pTaskData, error->status); |
930 | 896 | log_d("<< Service Discovered");
|
931 | 897 | return error->status;
|
932 | 898 | }
|
933 | 899 |
|
934 | 900 | std::map<std::string, BLERemoteService *> *BLEClient::getServices() {
|
935 |
| -/* |
936 |
| -* Design |
937 |
| -* ------ |
938 |
| -* We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the |
939 |
| -* peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT |
940 |
| -* and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. |
941 |
| -*/ |
942 | 901 | log_v(">> getServices");
|
943 |
| -// TODO implement retrieving services from cache |
944 |
| -//m_semaphoreSearchCmplEvt.take("getServices"); |
| 902 | + |
945 | 903 | clearServices(); // Clear any services that may exist.
|
946 | 904 |
|
| 905 | +if (!isConnected()) { |
| 906 | +log_e("Disconnected, could not retrieve services -aborting"); |
| 907 | +return &m_servicesMap; |
| 908 | +} |
| 909 | + |
947 | 910 | int errRc = 0;
|
948 |
| -TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); |
949 |
| -ble_task_data_t taskData = {this, cur_task, 0, nullptr}; |
| 911 | +BLETaskData taskData(this); |
950 | 912 |
|
951 | 913 | errRc = ble_gattc_disc_all_svcs(m_conn_id, BLEClient::serviceDiscoveredCB, &taskData);
|
| 914 | + |
952 | 915 | if (errRc != 0) {
|
953 | 916 | log_e("ble_gattc_disc_all_svcs: rc=%d %s", errRc, BLEUtils::returnCodeToString(errRc));
|
954 | 917 | m_lastErr = errRc;
|
955 |
| -//m_semaphoreSearchCmplEvt.give(); |
956 | 918 | return &m_servicesMap;
|
957 | 919 | }
|
958 |
| -// If successful, remember that we now have services. |
959 |
| -m_haveServices = m_servicesMap.size() > 0; |
960 |
| -//m_semaphoreSearchCmplEvt.give(); |
961 |
| -log_v("<< getServices"); |
| 920 | + |
| 921 | +BLEUtils::taskWait(taskData, BLE_NPL_TIME_FOREVER); |
| 922 | +errRc = taskData.m_flags; |
| 923 | +if (errRc == 0 || errRc == BLE_HS_EDONE) { |
| 924 | +// If successful, remember that we now have services. |
| 925 | +m_haveServices = m_servicesMap.size() > 0; |
| 926 | +log_v("<< getServices"); |
| 927 | +return &m_servicesMap; |
| 928 | +} |
| 929 | + |
| 930 | +m_lastErr = errRc; |
| 931 | +log_e("Could not retrieve services, rc=%d %s", errRc, BLEUtils::returnCodeToString(errRc)); |
962 | 932 | return &m_servicesMap;
|
963 | 933 | } // getServices
|
964 | 934 |
|
965 | 935 | int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
966 | 936 | BLEClient *client = (BLEClient *)arg;
|
967 |
| -int rc; |
| 937 | +int rc = 0; |
| 938 | +BLETaskData *pTaskData = client->m_pTaskData; |
968 | 939 |
|
969 | 940 | log_d("BLEClient", "Got Client event %s", BLEUtils::gapEventToString(event->type));
|
970 | 941 |
|
@@ -979,7 +950,7 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
979 | 950 | case BLE_HS_ETIMEOUT_HCI:
|
980 | 951 | case BLE_HS_ENOTSYNCED:
|
981 | 952 | case BLE_HS_EOS:
|
982 |
| -log_d("BLEClient", "Disconnect - host reset, rc=%d", rc); |
| 953 | +log_e("BLEClient", "Disconnect - host reset, rc=%d", rc); |
983 | 954 | BLEDevice::onReset(rc);
|
984 | 955 | break;
|
985 | 956 | default:
|
@@ -990,14 +961,12 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
990 | 961 | break;
|
991 | 962 | }
|
992 | 963 |
|
993 |
| -// Stop the disconnect timer since we are now disconnected. |
994 |
| -ble_npl_callout_stop(&client->m_dcTimer); |
995 |
| - |
996 | 964 | // Remove the device from ignore list so we will scan it again
|
997 | 965 | // BLEDevice::removeIgnored(client->m_peerAddress);
|
998 | 966 |
|
999 | 967 | // No longer connected, clear the connection ID.
|
1000 | 968 | client->m_conn_id = BLE_HS_CONN_HANDLE_NONE;
|
| 969 | +client->m_terminateFailCount = 0; |
1001 | 970 |
|
1002 | 971 | // If we received a connected event but did not get established (no PDU)
|
1003 | 972 | // then a disconnect event will be sent but we should not send it to the
|
@@ -1028,11 +997,11 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
1028 | 997 |
|
1029 | 998 | rc = event->connect.status;
|
1030 | 999 | if (rc == 0) {
|
1031 |
| -log_i("BLEClient", "Connected event"); |
| 1000 | +log_i("BLEClient: Connected event. Handle: %d", event->connect.conn_handle); |
1032 | 1001 |
|
1033 | 1002 | client->m_conn_id = event->connect.conn_handle;
|
1034 | 1003 |
|
1035 |
| -rc = ble_gattc_exchange_mtu(client->m_conn_id, NULL, NULL); |
| 1004 | +rc = ble_gattc_exchange_mtu(client->m_conn_id, nullptr, nullptr); |
1036 | 1005 | if (rc != 0) {
|
1037 | 1006 | log_e("BLEClient", "MTU exchange error; rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
|
1038 | 1007 | break;
|
@@ -1049,6 +1018,20 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
1049 | 1018 | return 0;
|
1050 | 1019 | } // BLE_GAP_EVENT_CONNECT
|
1051 | 1020 |
|
| 1021 | +case BLE_GAP_EVENT_TERM_FAILURE: { |
| 1022 | +if (client->m_conn_id != event->term_failure.conn_handle) { |
| 1023 | +return 0; |
| 1024 | +} |
| 1025 | + |
| 1026 | +log_e("Connection termination failure; rc=%d - retrying", event->term_failure.status); |
| 1027 | +if (++client->m_terminateFailCount > 2) { |
| 1028 | +ble_hs_sched_reset(BLE_HS_ECONTROLLER); |
| 1029 | +} else { |
| 1030 | +ble_gap_terminate(event->term_failure.conn_handle, BLE_ERR_REM_USER_CONN_TERM); |
| 1031 | +} |
| 1032 | +return 0; |
| 1033 | +} // BLE_GAP_EVENT_TERM_FAILURE |
| 1034 | + |
1052 | 1035 | case BLE_GAP_EVENT_NOTIFY_RX:
|
1053 | 1036 | {
|
1054 | 1037 | if (client->m_conn_id != event->notify_rx.conn_handle) {
|
@@ -1236,12 +1219,8 @@ int BLEClient::handleGAPEvent(struct ble_gap_event *event, void *arg) {
|
1236 | 1219 | }
|
1237 | 1220 | } // Switch
|
1238 | 1221 |
|
1239 |
| -if (client->m_pTaskData != nullptr) { |
1240 |
| -client->m_pTaskData->rc = rc; |
1241 |
| -if (client->m_pTaskData->task) { |
1242 |
| -xTaskNotifyGive(client->m_pTaskData->task); |
1243 |
| -} |
1244 |
| -client->m_pTaskData = nullptr; |
| 1222 | +if (pTaskData != nullptr) { |
| 1223 | +BLEUtils::taskRelease(*pTaskData, rc); |
1245 | 1224 | }
|
1246 | 1225 |
|
1247 | 1226 | return 0;
|
@@ -1256,41 +1235,16 @@ int BLEClient::disconnect(uint8_t reason) {
|
1256 | 1235 | int rc = 0;
|
1257 | 1236 |
|
1258 | 1237 | if(isConnected()) {
|
1259 |
| -// If the timer was already started, ignore this call. |
1260 |
| -if(ble_npl_callout_is_active(&m_dcTimer)) { |
1261 |
| -log_i("Already disconnecting, timer started"); |
1262 |
| -return BLE_HS_EALREADY; |
1263 |
| -} |
1264 |
| - |
1265 |
| -ble_gap_conn_desc desc; |
1266 |
| -if(ble_gap_conn_find(m_conn_id, &desc) != 0){ |
1267 |
| -log_i("Connection ID not found"); |
1268 |
| -return BLE_HS_EALREADY; |
1269 |
| -} |
1270 |
| - |
1271 |
| -// We use a timer to detect a controller error in the event that it does |
1272 |
| -// not inform the stack when disconnection is complete. |
1273 |
| -// This is a common error in certain esp-idf versions. |
1274 |
| -// The disconnect timeout time is the supervison timeout time + 1 second. |
1275 |
| -// In the case that the event happenss shortly after the supervision timeout |
1276 |
| -// we don't want to prematurely reset the host. |
1277 |
| -ble_npl_time_t ticks; |
1278 |
| -ble_npl_time_ms_to_ticks((desc.supervision_timeout + 100) * 10, &ticks); |
1279 |
| -ble_npl_callout_reset(&m_dcTimer, ticks); |
1280 |
| - |
1281 | 1238 | rc = ble_gap_terminate(m_conn_id, reason);
|
1282 |
| -if (rc != 0) { |
1283 |
| -if(rc != BLE_HS_EALREADY) { |
1284 |
| -ble_npl_callout_stop(&m_dcTimer); |
1285 |
| -} |
| 1239 | +if (rc != 0 && rc != BLE_HS_ENOTCONN && rc != BLE_HS_EALREADY) { |
| 1240 | +m_lastErr = rc; |
1286 | 1241 | log_e("ble_gap_terminate failed: rc=%d %s", rc, BLEUtils::returnCodeToString(rc));
|
1287 | 1242 | }
|
1288 | 1243 | } else {
|
1289 | 1244 | log_d("Not connected to any peers");
|
1290 | 1245 | }
|
1291 | 1246 |
|
1292 | 1247 | log_d("<< disconnect()");
|
1293 |
| -m_lastErr = rc; |
1294 | 1248 | return rc;
|
1295 | 1249 | } // disconnect
|
1296 | 1250 |
|
|
0 commit comments