BLE Disconnect works but then reconnects

,

I have a photon 2 acting as a peripheral to my iPhone which is acting as the central. The photon 2 is meant to advertise, and when connected to my the iPhone, receive a timestamp from the phone, and then the p2 should disconnect. Basically stop advertising and move on. Unfortunately as soon as the disconnect occurs a new connection is made. The iPhone is constantly scanning for the p2 and will attempt connection when it receives it advertisement but the P2 says it is no longer advertising but for some reason the connection continues to be made. Is this a bug in the BLE stack? Here is my simplified code.


#include "Particle.h"

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

const char *BLT_DEVICE_NAME = "BLT_dev01";
const char *BLT_SERVICE_UUID = "9f6e6f56-bbbb-4bcb-b213-ab2d0dc4ae37";
const char *BLT_TIME_UUID = "9f6e6f56-ab56-aaaa-b214-ab2d0dc4ae37";
void onTimeDataReceived(const uint8_t *data, size_t len, const BlePeerDevice &peer, void *context);

BleCharacteristic timeCharacteristic("time", BleCharacteristicProperty::WRITE, BLT_TIME_UUID, BLT_SERVICE_UUID, onTimeDataReceived);

BlePeerDevice iPhoneCentralDevice;
BleAdvertisingData advData;
volatile bool shouldDisconnect = false;

void onConnectedToPhone(const BlePeerDevice &peer, void *context)
{
  iPhoneCentralDevice = peer;
  Serial.println("Connected to phone with address " + iPhoneCentralDevice.address().toString());
  BLE.stopAdvertising();
}

void setup()
{
  Serial.begin(9600);
  while (!Serial.isConnected())
  {
  }

  BLE.on();
  BLE.onConnected(onConnectedToPhone, NULL);
  BLE.addCharacteristic(timeCharacteristic);
  timeCharacteristic.onDataReceived(onTimeDataReceived, &timeCharacteristic);
  advData.appendServiceUUID(BLT_SERVICE_UUID);
  advData.deviceName((char *)BLT_DEVICE_NAME, strlen(BLT_DEVICE_NAME));
  BLE.setDeviceName(BLT_DEVICE_NAME);
  BLE.advertise(&advData);
  Serial.println("advertising...");
}

void loop()
{
  if (shouldDisconnect) {
    shouldDisconnect = false;
    Serial.println("Disconnecting...");
    BLE.stopAdvertising();
    if (BLE.advertising()) {
      Serial.println("still advertising....");
    } else {
      Serial.println("not advertising!");
    }
    iPhoneCentralDevice.disconnect();
  }
}

void onTimeDataReceived(const uint8_t *data, size_t len, const BlePeerDevice &peer, void *context)
{
  Serial.println("got time");
  shouldDisconnect = true;
}

Here is my log

Disconnecting...
not advertising!
Connected to phone with address 46:B4:79:D6:1A:04
got time
Disconnecting...
not advertising!
Connected to phone with address 46:B4:79:D6:1A:04
got time
Disconnecting...
not advertising!
Connected to phone with address 46:B4:79:D6:1A:04
got time
Disconnecting...
not advertising!
Connected to phone with address 46:B4:79:D6:1A:04
got time
Disconnecting...
not advertising!
Connected to phone with address 46:B4:79:D6:1A:04
got time

This is being investigated. It appears that it may be a threading-related bug in Device OS. [This is being investigated, but the threading-related issue was a different bug report.]

Assume! Thanks @rickkas7

On a potentially related note, I have also determined that if the Photon 2 connects to the iPhone first as a peripheral it can no longer connect to another peripheral as a central. It discovers the device but then fails on the connect. However, if it connects to the advertising peripheral first it can then connect to the phone as a peripheral without issue. Not sure if this is related. Essentially my use case is this:

---> <Photon 2> ---> iPhone. (all over BLE)

Medical device is always a peripheral UART
Photon 2 is a central to the Medical Device and a Peripheral to the Phone
Phone is a central

This may be related, however I can post a new topic on this if necessary along with code to duplicate.

Hi, you might have an issue right there:

Remember:

Also, no BLE calls from inside a BLE handler. :skull:

Hey, I see there is A TON of fixes on BLE coming with DeviceOS 6.2.0:

Looks promising...

1 Like

Great catch @gusgonnet. Unfortunately I removed the call however the behavior still remains.

Also, are we saying that 6.2 will be for the Photon 2 as well?

When I use the device restore tool on a Photon 2, DeviceOS 6.2.0 shows up in the list to flash, so it might be. I'd like to get confirmation though...

Fingers crossed. :slight_smile:

Hey I see a 6.2 pre-release for the Photon 2 in VSCode this morning! @gusgonnet Going to see how my reconnection situation works out with the new device OS.

1 Like

Hi @iitgrad, all of the BLE.stopAdvertising(); in your source code is actually a no-op, since BLE is not advertising at the time the API is called and this API simply returns. If you want to stop advertising after disconnected, you are supposed to call this API after the disconnected callback is invoked.

In DVOS, BLE will restart advertising automatically after disconnected from BLE central device. There is no wiring API to disable this feature as of right now.

BTW, what is the mobile app that you were using to send the time to Photon2? Does it keep scanning for your specific Photon2s and connect to it once scanned?

2 Likes

Well, unfortunately, no improvement on this with 6.2. Dang it! @gusgonnet @rickkas7

unfortunately, no improvement on this with 6.2.
Sad to hear.

Hey, from what Guohui Xu says here:

You might need to modify the logic of your mobile app, could it be?

Hi @ielec

Interesting. I moved my BLE.stopAdvertising() to just after the disconnect and it worked! Hooray. Thanks so much for that insight.

Now I want to go back to 5.9 just to confirm the same behavior there.

Glad to hear it worked for you! We'll discuss internally to see whether we should expose a wiring API to disable the "disconnect to restart advertising" feautre.

Regarding your question of the iPhone app. Yes, it is always scanning for this peripheral as I need it to to get a connection when the peripheral needs the connection, however, I need the peripheral to make that decision on its own which is why the ability for it to get its time and then disconnect on its own was important.

That makes sense. In that case, a wiring API to disable the feature I mentioned is necessary.

I guess my only thought on this is that there was a perception on my part that

  1. during a connection there is no advertising
  2. if advertising is enabled, as soon as there is a disconnect, the advertising would be immediately reinitiated before I could turn it off

which is why I just wanted to disable advertising such that whenever the device was not connected it would choose not to advertise until directed to do so.