esp32-snippets icon indicating copy to clipboard operation
esp32-snippets copied to clipboard

BLE client gets stuck while calling BLEClient::connect()

Open TSOgang opened this issue 6 years ago • 52 comments

First of all, hello and thank you for your libraries and excuse me for this probably very simple question.

Very recently I have begun learning BLE and the esp32 and my goal for the moment is to successully establish a BLE connection between an esp32 (as client) and the nRF52 (as server). I believe the nRF52 works, since I can connect to it using my phone and control the value of characteristics in it. However, I can't get the esp32 to connect to it successully. It is able to scan and detect nearby devices and find the nRF52's adress no problem, but when a connection attempt is made using the connect() function, the program seems to wait indefinitely and no connection is ever established. While I have done some research on semaphores, I am still quite unfamilliar with them.

I wish to understand where it gets stuck in the connect() fuction, why it does that and how can I make it work. Here is my code (I am using the Arduino framework in PlatformIO):

#include <Arduino.h>

#include "BLEDevice.h"


static BLEUUID serviceUUID("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
static BLEUUID characteristicUUID("0000004f-0000-1000-8000-00805f9b34fb");
String My_BLE_Address = "d1:c7:bd:79:c4:05";

static BLERemoteCharacteristic* pRemoteCharacteristic;
BLEScan* pBLEScan;
BLEScanResults foundDevices;
static BLEAddress *Server_BLE_Address;
String Scanned_BLE_Address;

boolean paired = false;      // Flag verifying if we are paired with our device
boolean foundDevice = false; // Flag verifying if we found our device

bool connectToserver (BLEAddress pAddress){
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");
     
     
    // Connect to the BLE Server.
    pClient->connect(pAddress); // Stuck here...
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService != nullptr)
    {
      Serial.println(" - Found our service");
      return true;
    }
    else
    return false;

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(characteristicUUID);
    if (pRemoteCharacteristic != nullptr)
      Serial.println(" - Found our characteristic");

      return true;
}

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks 
{ 
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      Serial.printf("Scan Result: %s \n", advertisedDevice.toString().c_str());
      if(foundDevice == false){   // Flag verifying if we found our device
      Server_BLE_Address = new BLEAddress(advertisedDevice.getAddress()); // Update Server_BLE_Address if we didn't
      Scanned_BLE_Address = Server_BLE_Address->toString().c_str();
      }
      if(Scanned_BLE_Address == My_BLE_Address) // Compares the scanned adress to what we are looking for
      {
        foundDevice = true; // Found our device
      }
      Serial.println("Comparing to our server adress: ");
      Serial.println(My_BLE_Address);
    }
};

void setup() {
    Serial.begin(115200); //Start serial monitor 
    Serial.println("ESP32 BLE Client program"); //Intro message 

    BLEDevice::init("ESP32");
    pBLEScan = BLEDevice::getScan(); //create new scan
    pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); //Call the class that is defined above 
    pBLEScan->setActiveScan(false); //active scan uses more power, but get results faster
}

void loop() {

  foundDevices = pBLEScan->start(3); //Scan for 3 seconds to find the server
  uint8_t devicesCount = foundDevices.getCount(); 
  Serial.printf("%d devices found \n", devicesCount);
  while (devicesCount >= 1 && foundDevice == true) // We found our server
  {
    if (foundDevice == true && paired == false) // We're not connected yet
    {
      Serial.println("Found our Device... connecting to Server as client \n");
       if (connectToserver(*Server_BLE_Address)) // Attempt a connection to the server   ...Stuck here...
      {
      paired = true;
      Serial.println("********************CONNECTED TO SERVER************************");
     
      break;
      }
      else
      {
      Serial.println("Pairing failed");
      foundDevice = false;
      break;
      }
    }
    devicesCount = 0; // Reset the number of devices
  }
  pBLEScan->stop();
  delay(5000);
}

And here is what the serial monitor looks like:

ESP32 BLE Client program
Scan Result: Name: , Address: 3f:43:89:02:09:99, manufacturer data: 0600010920020273111e440a64443a2bbdb913d98c83605f724bf88dd6
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 21:5f:63:6c:59:18, manufacturer data: 0600010920024cbbbc219822bf9d445e8c12280b7f0e218a9c491fd485
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 22:08:60:11:95:b3, manufacturer data: 06000109200267b9b0dc5ac0c049f892ec1bb09f3afed1bac30914b6fb
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 3b:e3:63:51:43:55, manufacturer data: 060001092002578fe17a471e0a3fff4cb07172df27a10fc4835298acd4
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: nRF52, Address: d1:c7:bd:79:c4:05, txPower: 4
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 04:b3:68:61:52:c6, manufacturer data: 060001092002810c02a9395aa4bc0d6ca4ee830ff5dc8f1dfc49e15e74
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 74:97:07:46:24:ca, manufacturer data: 4c001005131cc48f22
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 08:c0:21:ff:af:48, manufacturer data: 060001092002585e2df55dd581bf04830fe41d2f2d0cd131b433f79c76
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: f4:5c:89:a7:90:36, manufacturer data: 4c0010050b1c604ec2
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 52:33:f9:76:9e:a1, manufacturer data: 4c000c0e00f2e83ef80545a417a96ba8e194
Comparing to our server adress:
d1:c7:bd:79:c4:05
Scan Result: Name: , Address: 7c:87:5c:cc:fd:c8, manufacturer data: 4c0010050318008367
Comparing to our server adress:
d1:c7:bd:79:c4:05
11 devices found
Found our Device... connecting to Server as client

 - Created client

Do you think you can help me? Thanks in advance.

TSOgang avatar May 27 '19 17:05 TSOgang

Same issue here. I noticed that after a reset on the client this happens, after resetting once or twice again it reconnects.

rmnaderdev avatar May 30 '19 21:05 rmnaderdev

It can be few reasons, but if i would have to guess its because in arduino version there is still few bugs. My advice is to use this library instead, or to find someone who will update arduino version.

chegewara avatar May 30 '19 21:05 chegewara

I am having the same issue.

Greenstreem avatar Jun 02 '19 23:06 Greenstreem

Please excuse for my silence, I have stopped working on the esp-32 (a little bit out of frustration) to concentrate on the other chip im working on. This morning I wanted to try again from the beginning and simply copy pasted the client example in the "ESP32 BLE Arduino" library (that I have tried before without success) and changed up the Uuids to match my other chip's Uuids.

I gave it a go and it...connected successfully without trouble... My best guess would be that my problem was on the server side, and since I worked on it, I must have corrected the problem without realising it. I am still unsure as to why my program got stuck in the connect() function (and I see im not the only one), so I won't close this issue just yet.

If there is one thing I know it's that the problem dosen't seem to come from the libraries (since it worked), but I can't know for sure.

TSOgang avatar Jun 03 '19 14:06 TSOgang

Hi! I'm also using Arduino to program ESP32. This issue is very frustrating. I don't have solution for this problem, but I have noticed that it occurs when there are lot of scanned devices. It looks that code stucks on that line: BLERemoteService* pRemoteService = pClient->getService(serviceUUID); in Client example.

Any ideas how to fix this?

majstor12 avatar Jun 03 '19 19:06 majstor12

@majstor12 yes, use this repository instead of arduino library. In arduino library is some bug that has been fixed here long time ago (few other bugs too).

chegewara avatar Jun 04 '19 10:06 chegewara

Do we expect to have these changes/improvements propagated to arduino library and how? we see following update having made significant changes, but could not find which issues it is fixing: https://github.com/nkolban/esp32-snippets/commit/e6d9ff2b9ec8adbccd7d629e85fb419c9d56a9e4

arsab avatar Jun 23 '19 17:06 arsab

@chegewara Might be a silly question, how can I use this repository instead of arduino library? Can you please teach me how to do that?

YeonwooSung avatar Jun 29 '19 16:06 YeonwooSung

https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/ArduinoBLE.md

chegewara avatar Jun 29 '19 17:06 chegewara

@chegewara Thanks :)

YeonwooSung avatar Jun 30 '19 05:06 YeonwooSung

Hi, I have got the same problem // ------------------------------- pClient->connect(pAddress); // Stuck here... //-------------------------------- I solved this problem by modifying the FreeRTOS.cpp file. You can see this command in line 77 of FreeRTOS.cpp xSemaphoreTake(m_semaphore, portMAX_DELAY); As the portMAX_DELAY value is 0xffffffffUL, maybe the code will wait for about 50 days to connect to the BLE device. So that, I changed the code like this and my code didn't get stuck anymore. xSemaphoreTake(m_semaphore, 60000);

Thanks.

EngineeringStar avatar Aug 11 '19 09:08 EngineeringStar

So that, I changed the code like this and my code didn't get stuck anymore. xSemaphoreTake(m_semaphore, 60000);

Thanks for sharing your hang workaround. Instead of 60000 I'm using 15000; The smaller value works well for me (shorter "hang" times).

  • Thomas

thomastech avatar Oct 28 '19 20:10 thomastech

Thanks for your notice, Thomas.

EngineeringStar avatar Oct 28 '19 21:10 EngineeringStar

@jiangminghe During validation I found another xSemaphoreTake() that caused an endless hang in my client application. This required another workaround patch at line 198: I changed the timeout to 15 seconds, as follows: rc = ::xSemaphoreTake(m_semaphore, 15000UL) == pdTRUE;

I recognize that these edits are workarounds, not permanent patches. But I will use them until the semaphore issues are resolved.

  • Thomas

thomastech avatar Oct 31 '19 02:10 thomastech

Patch that is fixing semaphores issue has been added to arduino-esp32 repository some time ago. Because code in BLEClient is just a bit different the same patch didnt work here, or maybe i was not lucky.

chegewara avatar Nov 01 '19 21:11 chegewara

I'm using the latest arduino-esp32 repository (last patch was from about 30 days ago). If there are more recent semaphore fixes then I would definitely want to try them out.

  • Thomas

thomastech avatar Nov 02 '19 00:11 thomastech

Sorry, it was the latest one, in this case there is somewhere else semaphore that causing stuck.

chegewara avatar Nov 02 '19 00:11 chegewara

I tried replacing the libraries as suggested by @chegewara , I see no change. The program still gets stuck.

Prathik-Jain avatar Jan 07 '20 10:01 Prathik-Jain

Hi, I am having this issue as well:

`bool connectToServer() {

BLEClient*  pClient  = BLEDevice::createClient();
pClient->setClientCallbacks(new MyClientCallback());

// Connect to the remote BLE Server.
Serial.printf("Connecting to %s.\n", serverAddress);
//Serial.println(myDevice->getAddress().toString().c_str());
pClient->connect(BLEAddress(serverAddress)); //myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)

//**** MANY TIMES, DOES NOT EXECUTE CODE BELOW ****//

// Obtain a reference to the service we are after in the remote BLE server.
pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == NULL) {
  Serial.println("Service not found.");
  M5.Lcd.println("Service not found.");
  M5.update();
  pClient->disconnect();
  return false;
}
Serial.println("Service found.");
M5.Lcd.println("Service found.");
M5.update();

}`

Any new updates, @chegewara?

ufanders avatar Jan 25 '20 23:01 ufanders

It is possible that calling this line: pClient->connect(BLEAddress(serverAddress)); //myDevice); not necessarily ends with connecting to peer device. I would suggest to add additional check after this line:

if(!pClient->isConnected())
    return false;

Also changing semaphore to timed semaphore as many times was suggested is good idea.

chegewara avatar Jan 26 '20 20:01 chegewara

Ok thanks I'll try the timed semaphore fix.

ufanders avatar Jan 28 '20 03:01 ufanders

You can not connect while scanning. Stop scanning first.

BojanJurca avatar Feb 11 '20 19:02 BojanJurca

While reading #757 I have found that connect call can actually take two arguments - BLEAddress as the first one and esp_ble_addr_type_t type as a second (optional) argument that defaults to BLE_ADDR_TYPE_PUBLIC. However, as mentioned, "most if not all smartphones, tablets and laptops are using random addressing" and esp_ble_addr_type_t type has to be set to BLE_ADDR_TYPE_RANDOM (https://github.com/nkolban/esp32-snippets/issues/757#issuecomment-448336410). Worked for me!

ravsten avatar Mar 03 '20 21:03 ravsten

@ravsten There is overloaded connect function, which will figure out address type, but you need to pass advertised device instead of address.

chegewara avatar Mar 03 '20 21:03 chegewara

@ravsten There is overloaded connect function, which will figure out address type, but you need to pass advertised device instead of address.

To avoid misleading anyone I want to mention that I am using an Arduino built-in BLE ESP32 library so I guess that is why I pass BLEAddress instead of BLEDevice. Correct @chegewara?

ravsten avatar Mar 04 '20 17:03 ravsten

https://github.com/espressif/arduino-esp32/blob/master/libraries/BLE/src/BLEClient.h#L36

chegewara avatar Mar 04 '20 17:03 chegewara

Ok thanks I'll try the timed semaphore fix.

Hello, could you share with us how to do it? :)

vcmorini avatar Mar 07 '20 22:03 vcmorini

Hi I'm having the same issue here. I'm trying to connect 2 ESP32, one as a Client and the other one as a Server. The Client is stuck in connect(myAdvDevice) line. Is there any update here? The semaphores fix is the only option?

I'm using the Arduino library. Thanks.

xsaco07 avatar May 28 '20 06:05 xsaco07

I edited the FreeRTOS.cpp file, changing the xSemaphoreTake() parameter to 15000UL as mentioned in the comments and I'm not getting the result expected yet. It is still getting stuck on the connect(myAdvDecice) function call.

xsaco07 avatar Jun 07 '20 19:06 xsaco07

Check the file again and confirm you have changed ALL the occurrences of xSemaphoreTake() that used the portMAX_DELAY to 15000UL. If you've already done that then I doubt your issue is due to the semaphore timeout hang issue.

  • Thomas

thomastech avatar Jun 07 '20 23:06 thomastech