Skip to content

BLE.scan(true) stopped after 10-15 minutes #202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
murali-dotworld opened this issue Sep 20, 2021 · 5 comments · Fixed by #264
Open

BLE.scan(true) stopped after 10-15 minutes #202

murali-dotworld opened this issue Sep 20, 2021 · 5 comments · Fixed by #264
Labels
status: waiting for information More information must be provided before work can proceed topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project

Comments

@murali-dotworld
Copy link

murali-dotworld commented Sep 20, 2021

Hello, I have used nano ble 33 module. I am connect to the peripheral device and getting data, while allows a scan with duplicates.
But the scan stops automatically 10-15 minutes. Can you suggest way for continous scan

#include<ArduinoBLE.h>

String compare = "fd05a570-274a-4b1f-a5a3-eb52e5e02b8b";
void setup() {
  Serial.begin(115200);
  while (!Serial);
  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }
  //BLE.debug(Serial);
  Serial.println("BLE Central - Peripheral Explorer");
  // start scanning for peripherals
  //BLE.debug(Serial1);
  BLE.scan(true);
}
void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();
  if (peripheral)
  {
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.print("' ");
    Serial.print("RSSI  :");
    Serial.println(peripheral.rssi());
    String compare = "fd05a570-274a-4b1f-a5a3-eb52e5e02b8b";
    if (peripheral.rssi() > -55)
    {
      String compare = "fd05a570-274a-4b1f-a5a3-eb52e5e02b8b";
      if (peripheral.advertisedServiceUuid() == compare)
      {
        BLE.stopScan();
        explorerPeripheral(peripheral);
        BLE.scan(true);
      }
    }
  }
}
void explorerPeripheral(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");
  if (peripheral.connect())
  {
    Serial.println("Connected");
  }
  else
  {
    Serial.println("Failed to connect!");
    return;
  }
  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }
  // read and print device name of peripheral
  Serial.println();
  Serial.print("Device name: ");
  Serial.println(peripheral.deviceName());
  Serial.print("Appearance: 0x");
  Serial.println(peripheral.appearance(), HEX);
  Serial.println();
  // loop the services of the peripheral and explore each
  for (int i = 0; i < peripheral.serviceCount(); i++)
  {
    BLEService service = peripheral.service(i);
    exploreService(service);
  }
  Serial.println();
  // we are done exploring, disconnect
  Serial.println("Disconnecting ...");
  peripheral.disconnect();
  Serial.println("Disconnected");
}

void exploreService(BLEService service) {
  // print the UUID of the service
  Serial.print("Service ");
  Serial.println(service.uuid());
  String comp = "fd05a570-274a-4b1f-a5a3-eb52e5e02b8b";
  if (service.uuid() == comp)
  {
    // loop the characteristics of the service and explore each
    for (int i = 0; i < service.characteristicCount(); i++) {
      BLECharacteristic characteristic = service.characteristic(i);
      exploreCharacteristic(characteristic);
    }
  }
}
void exploreCharacteristic(BLECharacteristic characteristic) {
  // print the UUID and properties of the characteristic
  Serial.print("\tCharacteristic ");
  Serial.print(characteristic.uuid());
  Serial.print(", properties 0x");
  Serial.print(characteristic.properties(), HEX);
  // check if the characteristic is readable
  if (characteristic.canRead()) {
    // read the characteristic value
    characteristic.read();
    if (characteristic.valueLength() > 0) {
      // print out the value of the characteristic
      Serial.print(", value 0x");
      printData(characteristic.value(), characteristic.valueLength());
      characteristic.writeValue((byte)0x01);
    }
  }
  Serial.println();
}

void exploreDescriptor(BLECharacteristic characteristic) {
  if (characteristic.canRead()) {
    characteristic.read();
    if (characteristic.valueLength() > 0) {
      Serial.print("Value: ");
      printData(characteristic.value(), characteristic.valueLength());
      characteristic.writeValue((byte)0x01);
    }
  }
  Serial.println();
  //  // print the UUID of the descriptor
  //  Serial.print("\t\tDescriptor ");
  //  Serial.println(descriptor.uuid());
  //  // read the descriptor value
  //  descriptor.read();
  //  // print out the value of the descriptor
  //  Serial.print("value:");
  //  printData(descriptor.value(), descriptor.valueLength());
  //  Serial.println();
}
void printData(const unsigned char data[], int length)
{
  for (int i = 0; i < length; i++)
  {
    unsigned char b = data[i];
    if (b < 16) {
      Serial.print("0");
    }
    Serial.print(String((char)b));
  }
}
@2Eagle2
Copy link

2Eagle2 commented Sep 28, 2021

Hi I had similar issue - it turns out to be problem when multiple devices advertise at the same time and there is collision resulting in disrupted package not detected in HCI.cpp
I have made following change om poll method which solved my freezing issue:

void HCIClass::poll(unsigned long timeout)
{
#ifdef ARDUINO_AVR_UNO_WIFI_REV2
  digitalWrite(NINA_RTS, LOW);
#endif

  if (timeout) {
    HCITransport.wait(timeout);
  }

  while (HCITransport.available()) {
    byte b = HCITransport.read();

    _recvBuffer[_recvIndex++] = b;

    if (_recvBuffer[0] == HCI_ACLDATA_PKT) {
      if (_recvIndex > 5 && _recvIndex >= (5 + (_recvBuffer[3] + (_recvBuffer[4] << 8)))) {
        if (_debug) {
          dumpPkt("HCI ACLDATA RX <- ", _recvIndex, _recvBuffer);
        }
#ifdef ARDUINO_AVR_UNO_WIFI_REV2
        digitalWrite(NINA_RTS, HIGH);
#endif
        int pktLen = _recvIndex - 1;
        _recvIndex = 0;

        handleAclDataPkt(pktLen, &_recvBuffer[1]);

#ifdef ARDUINO_AVR_UNO_WIFI_REV2
        digitalWrite(NINA_RTS, LOW);  
#endif
      } 
    } // FIX START
    else if (_recvBuffer[0] == HCI_EVENT_PKT) {
      if (_recvIndex >  1 && _recvBuffer[1] != EVT_DISCONN_COMPLETE
                          && _recvBuffer[1] != EVT_CMD_COMPLETE    
                          && _recvBuffer[1] != EVT_CMD_STATUS      
                          && _recvBuffer[1] != EVT_NUM_COMP_PKTS   
                          && _recvBuffer[1] != EVT_LE_META_EVENT)
      {
        // the packed is mishmash
        if (_debug) {
          dumpPkt("delete bad HCI EVENT RX <- ", _recvIndex, _recvBuffer);
        }
        // shift package one byte left - remove first invalid byte
        for (int ii = 1; ii < _recvIndex; ii++)
        {
          _recvBuffer[ii - 1] = _recvBuffer[ii];
        }
        _recvIndex--;
      } 
      else if (_recvIndex > 3 && _recvIndex >= (3 + _recvBuffer[2])) {
        if (_debug) {
          dumpPkt("HCI EVENT RX <- ", _recvIndex, _recvBuffer);
        }
#ifdef ARDUINO_AVR_UNO_WIFI_REV2
        digitalWrite(NINA_RTS, HIGH);
#endif
        // received full event
        int pktLen = _recvIndex - 1;
        _recvIndex = 0;

        handleEventPkt(pktLen, &_recvBuffer[1]);

#ifdef ARDUINO_AVR_UNO_WIFI_REV2
        digitalWrite(NINA_RTS, LOW);
#endif
      }   // FIX END
    } else {
      _recvIndex = 0;

      if (_debug) {
        _debug->println(b, HEX);
      }
    }
  }

#ifdef ARDUINO_AVR_UNO_WIFI_REV2
  digitalWrite(NINA_RTS, HIGH);
#endif
}

Deeper explonation:
When packet collision occure the first byte of other packet is also received which result in duplicite first byte:
0x0404 ... instead of just one. that byte is invalid and result in infinite loop in above cycle.
When such a packet is detected it is reported in debug stream and first byte is removed - whole buffer is shifted...

since then I have never encounter a freeze on my Arduino Nano 33 BLE again. (run several hours)
If it solve also your use case, I can make commit and suggest pull request if there is interest in such fix.

@murali-dotworld
Copy link
Author

Thank you for replying us. I have made a changes to it. I have checked it run around 3hours and stopped. After 2 hours, it is restarted automatically (I think so restarted with watchdog timer). My application is open a barricade when the bluetooth android device near nano 33 ble. Can you tell me any indication if the ble scan is stopped, so that i can reset the ble module with NVIC_SystemReset(). can you help me please

@2Eagle2
Copy link

2Eagle2 commented Oct 21, 2021

Hi - sorry I do not use this library anymore (we have switched to Zaphyr OS)
The symptoms of frozen ble library is infinite cycle of while loop.
As a detection of frozen ble library I would use some logical timeout:
First byte which come - mark millis()
Pseudocode to modify upper posted code:

// code until while
while (HCITransport.available()) {
byte b = HCITransport.read();

// checking size
if (sizeof(_recvBuffer) <= _recvIndex)
{
  _recvIndex = 0;
  if (_debug) {
        _debug->println("receive packet timeout");
      }
  continue;
}

// checking timeout 
if (_recvIndex == 0)
{ start_time = millis(); }
else if ((millis()-start_time) > threshold)
{
  _recvIndex = 0;
  if (_debug) {
        _debug->println("receive packet timeout");
      }
  continue;
}

// here the code continue 

then that to current millis on every loop and if it pass some threshold simply flush whole _recvBuffer and reset index.
another thing which need to be fixed is checking boundaries of _recvBuffer on line _recvBuffer[_recvIndex++] = b;
if it reach full buffer simply flush the buffer and and reset index.
(it can go off array when packed size is wrongly read and is bigger than the buffer, hich corrupt memory and make whole MCU freeze)
Yes - you make some packets lost in case of collision, but at least it make your MCU run flawlesly

@bigbearishappy
Copy link
Contributor

bigbearishappy commented Dec 7, 2021

I have made following change om poll method which solved my freezing issue:

you code is good to fix this problem.but it's not flexible.

In my condition.I have encountered with the packe start with 04 04 04 04 3E 1B 02

I replace the following code with mine:

// shift package one byte left - remove first invalid byte
        for (int ii = 1; ii < _recvIndex; ii++)
        {
          _recvBuffer[ii - 1] = _recvBuffer[ii];
        }
        _recvIndex--;

here is my code:

		int offset, cnt;
		for(offset = 0;offset < _recvIndex; ++offset){
			if(_recvBuffer[offset + 1] != HCI_EVENT_PKT && _recvBuffer[offset] == HCI_EVENT_PKT)
				break;
		}
		if(offset){
			for(cnt = offset;cnt < _recvIndex; ++cnt){
				_recvBuffer[cnt - offset] = _recvBuffer[cnt];
			}
		}
		_recvIndex -= offset;

@sallasia
Copy link
Contributor

Hi, try this:
ccdca60

@per1234 per1234 added type: imperfection Perceived defect in any part of project topic: code Related to content of the project itself status: waiting for information More information must be provided before work can proceed labels Oct 10, 2022
@per1234 per1234 linked a pull request Oct 10, 2022 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting for information More information must be provided before work can proceed topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants