espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
12.96k stars 7.29k forks source link

Cannot discover after connect #8861

Open benjasperson opened 7 months ago

benjasperson commented 7 months ago

Board

TTGO LoRa32-OLED

Device Description

NA

Hardware Configuration

NA

Version

v2.0.11

IDE Name

VS Code

Operating System

Windows 10

Flash frequency

80 MHz

PSRAM enabled

yes

Upload speed

921600

Description

Problem seems to be similar to https://github.com/espressif/arduino-esp32/issues/8448, but I don't see that the resolution solved anything (maybe it's actually a different issue). I cannot discover devices after successfully disconnecting. Discover fails because _isRemoteAdressSet is set to true. If however, I try to connect to a bad address (or just fail to connect to a valid address), I can scan again. The reason is because _isRemoteAddressSet is set to false after a failed connection attempt.

Workaround: Don't use disconnect. Instead, attempt connect to a false address, and when it fails, scan will work properly again.

Sketch

#include "BluetoothSerial.h"
#include <map>

BluetoothSerial SerialBT;
BTAddress savedAddresses[10];
int savedChannels[10];
int deviceCount = 0;
int selectedIdx = 0;
esp_spp_sec_t SEC_MASK=ESP_SPP_SEC_NONE;
esp_spp_role_t ROLE= ESP_SPP_ROLE_SLAVE; 
bool isConnected = false;    

void setup(){
    Serial.begin(115200);
    SerialBT.begin("ESP32", true);
    scan();
}

void loop(){
    BTAddress address;
    int channel = 0;
    bool success = false;
    isConnected = SerialBT.connected() && !SerialBT.isClosed();

    while(Serial.available()){
        char c = (char) Serial.read();
        int i = 0;
        switch (c)
        {
        case 'd':
            success = SerialBT.disconnect();
            Serial.printf("IsDisconnected = %d", success);
            break;
        case 'c':
            if(0 <= selectedIdx && selectedIdx < deviceCount){
                address = savedAddresses[selectedIdx];
                channel = savedChannels[selectedIdx];
            }
            success = SerialBT.connect(address, channel, SEC_MASK, ROLE);
            Serial.printf("IsConnected = %d\n", success);
            break;
        case '-':
            if(selectedIdx <= -1){
                selectedIdx = deviceCount - 1;
            } else {
                selectedIdx--;
            }
            Serial.printf("Selected index = %d\n", selectedIdx);
            break;
        case '+':
            if(selectedIdx >= deviceCount - 1){
                selectedIdx = -1;
            } else {
                selectedIdx++;
            }
            Serial.printf("Selected index = %d\n", selectedIdx);
            break;
        case 'p':
            Serial.printf("IsConnected = %d\nDeviceCount = %d\n", isConnected, deviceCount);
            for (i = 0; i < deviceCount; i++)
            {
                Serial.printf(" %d) %s\n", i, savedAddresses[i].toString(false).c_str());
            }

            break;
        case 's':
            scan();
            break;
        default:
            Serial.println("Serial commands:");
            Serial.println(" c - connect to device at selected index");
            Serial.println(" d - disconnect");
            Serial.println(" p - print list of disovered devices");
            Serial.println(" s - scan for devices");
            Serial.println(" -/+ - change selected index");
            if(c <= ' ' || '~' <= c){
                Serial.printf("Received val %d from Serial\n",(int) c);    
            } else {
                Serial.printf("Received %c from Serial\n", c);
            }
            break;
        }
    }

}

void scan(){
    deviceCount = 0;
    Serial.println("Starting discoverAsync...");
    BTScanResults * btDeviceList = SerialBT.getScanResults();  // maybe accessing from different threads!
    if (SerialBT.discoverAsync([](BTAdvertisedDevice* pDevice) {

    } )
    ) {
        delay(10000);
        Serial.print("Stopping discoverAsync... ");
        SerialBT.discoverAsyncStop();
        Serial.println("discoverAsync stopped");
        delay(5000);

        for (int i = 0; i < btDeviceList->getCount(); i++)
        {
            BTAdvertisedDevice *device=btDeviceList->getDevice(i);
            std::map<int,std::string> channels = SerialBT.getChannels(device->getAddress());
            Serial.printf("%s (%s), chnls = %d)\n", device->getName().c_str(), device->getAddress().toString().c_str(), channels.size());
            for(auto const &entry : channels) {
                Serial.printf("     channel %d (%s)\n", entry.first, entry.second.c_str());
            }
            savedAddresses[deviceCount] = device->getAddress();                
            if(channels.size() > 0) {                
                savedChannels[deviceCount++] = channels.begin()->first;
            } else {
                savedChannels[deviceCount++] = 0;
            }

        }
        Serial.printf("Found %d devices", deviceCount);

    } else {
        Serial.println("Error on discoverAsync");
    }
}

Debug Message

No error message.  Just fails to scan (due to _isRemoteAddressSet set to true).

Other Steps to Reproduce

Load the sketch, connect to a Serial monitor (baud rate 115200) and send 's' to scan, 'p' to print discovered devices, '-'/'+' to change the selected device index, 'c' to connect, or 'd' to disconnect.

Notice that you can scan as many times as you would like before connecting, but after connecting, the only only way to scan again is by first getting a failed connection attempt.

I have checked existing issues, online documentation and the Troubleshooting Guide

BlackWolfDEsign commented 3 months ago
void btDiscover() {
  BTScanResults* pScanResults = SerialBT.discover(BT_DISCOVER_TIME);

  if (pScanResults != nullptr && pScanResults->getCount() > 0) {
    for (int i = 0; i < pScanResults->getCount(); i++) {
      BTAdvertisedDevice* pDevice = pScanResults->getDevice(i);
      if (pDevice != nullptr) {
        String deviceName = pDevice->getName().c_str();
        if (deviceName.startsWith(SLAVE_NAME_PATTERN)) {
          delay(200);         // memory overload
          list.Add(deviceName);
        }
      }
    }
  }
}

works only in setup, it scans all available slaves and get the data from it via loop

for (int i = 0; i < list.Count(); i++) {
    SerialBT.connect(list[i]); // list should changed to string array or char or so
     //do some shit
  }

its helpful maybe