BLE fails to connect to peripheral as central after connecting as a peripheral to iPhone

,

This issue described below occurs on 5.9 and 6.2 on the photon 2

My scenario is that I have a medical device that is a UART peripheral and the P2 must detect and take is data and pass it on to the phone via BLE. The phone is a central and the P2 is a peripheral to the phone, and obviously a central to the medical device.

medical device --> P2 --> iPhone

If I connect to the medical device first, the p2 can then connect to the iPhone successfully after advertising without issue. However, the reverse does not work. If I connect to the iPhone first, then when scanning for the medical device, it detects it, but it fails to connect to it.

I have tried to reduce the code to a minimal set and make it easy to test the 2 scenarios with a couple of booleans.


#include "Particle.h"

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

// Case #1 - connect to medical device first then iPhone
volatile bool shouldBeScanning = true;
volatile bool shouldAdvertiseToIphone = false;

// Case #2 - connect to iPhone first then medical device
// volatile bool shouldBeScanning = false;
// volatile bool shouldAdvertiseToIphone = true;

SerialLogHandler logHandler(LOG_LEVEL_ALL, {
                                               // Logging level for non-application messages
                                               {"app", LOG_LEVEL_ALL} // Logging level for application messages
                                           });

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

const char *IMPLANT_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
const char *IMPLANT_TX_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
const char *IMPLANT_RX_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";

BleCharacteristic implantTXCharacteristic("implant_tx", BleCharacteristicProperty::NOTIFY, IMPLANT_TX_UUID, IMPLANT_SERVICE_UUID);
BleCharacteristic implantRXCharacteristic("implant_rx", BleCharacteristicProperty::WRITE_WO_RSP, IMPLANT_RX_UUID, IMPLANT_SERVICE_UUID);
BleCharacteristic timeCharacteristic("time", BleCharacteristicProperty::WRITE, BLT_TIME_UUID, BLT_SERVICE_UUID, onTimeDataReceived);

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

BleScanResult scanResults[20];
BleScanFilter filter = BleScanFilter();

BlePeerDevice implantDevice;
const unsigned long SCAN_PERIOD_MS = 2000;
unsigned long lastScan = 0;

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

void dataReceivedCallback(const uint8_t *data, size_t len, const BlePeerDevice &peer, void *context)
{
  Serial.print(".");
}

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);
  filter.serviceUUID(IMPLANT_SERVICE_UUID);
  BLE.advertise(&advData);
  implantRXCharacteristic.onDataReceived(dataReceivedCallback, &implantRXCharacteristic);
}

void loop()
{
  if (shouldAdvertiseToIphone)
  {
    BLE.advertise(&advData);
    if (!iPhoneCentralDevice.connected()) {
    Serial.println("advertising...");
    }
  }
  else
  {
    if (BLE.advertising())
    {
      BLE.stopAdvertising();
    }
  }

  if (!implantDevice.connected())
  {
    if (millis() - lastScan >= SCAN_PERIOD_MS && shouldBeScanning)
    {
      // Time to scan
      lastScan = millis();

      Serial.println("scanning for medical device...");
      auto results = BLE.scanWithFilter(filter);

      if (results.size() > 0)
      {
        auto result = results.first();
        Serial.println("found medical device, attempting to connect to " + result.address().toString() + " ...");
        implantDevice = BLE.connect(result.address());
        if (implantDevice.connected())
        {
          shouldBeScanning = false;
          Serial.println("successfully connected to medical device!");
          implantDevice.getCharacteristicByUUID(implantTXCharacteristic, IMPLANT_TX_UUID);
          implantDevice.getCharacteristicByUUID(implantRXCharacteristic, IMPLANT_RX_UUID);
          shouldAdvertiseToIphone = true;
        }
      }
    }
  }
  // if (shouldDisconnect)
  // {
  //   shouldDisconnect = false;
  //   Serial.println("Disconnecting...");
  //   if (BLE.advertising())
  //   {
  //     Serial.println("still advertising....");
  //   }
  //   else
  //   {
  //     Serial.println("not advertising!");
  //   }
  //   iPhoneCentralDevice.disconnect();
  //   BLE.stopAdvertising();
  // }
}

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

Running this code here is my output

l.ble] TRACE: Going to stop the stack...
0000002149 [hal] INFO: WiFi off
0000002158 [system.nm] INFO: State changed: NONE -> DISABLED
0000002174 [system.nm] TRACE: Interface 4 power state: DOWN
0000002212 [comm] INFO: channel inited
0000002233 [hal] INFO: rltk_wlan_set_netif_info: 0, 94:94:4a:04:08:38
0000002380 [hal] INFO: WiFi on
scanning for medical device...
found medical device, attempting to connect to 94:94:4A:04:C1:35 ...
0000007793 [wiring.ble] TRACE: Connected
0000007863 [wiring.ble] TRACE: New peripheral is connected.
0000007879 [wiring.ble] TRACE: Start discovering services.
0000008043 [wiring.ble] TRACE: Start discovering characteristics of service: 1801.
0000008312 [wiring.ble] TRACE: Characteristic discovered.
0000008314 [wiring.ble] TRACE: Start discovering characteristics of service: 1800.
0000008492 [wiring.ble] TRACE: Characteristic discovered.
0000008495 [wiring.ble] TRACE: Start discovering characteristics of service: 6FA90001-5C4E-48A8-94F4-8030546F36FC.
0000009122 [wiring.ble] TRACE: Characteristic discovered.
0000009125 [wiring.ble] TRACE: Start discovering characteristics of service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E.
0000009842 [wiring.ble] TRACE: Characteristic discovered.
successfully connected to medical device!
advertising...
advertising...
..advertising...
advertising...
advertising...
a..dvertising...
advertising...
advertising...
advertisi..ng...
advertising...
advertising...
advertising...
..advertising...
advertising...
advertising...
...advertising...
advertising...
advertising...
...Connected to phone with address 53:74:48:69:0D:C9
0000010570 [wiring.ble] TRACE: Connected
..0000010612 [system.ctrl.ble] TRACE: Connected
..........................................got time
...................................................................................................................................................................................................................................................................

One can see that the "Connected to phone" occurs as well as "got time". Additionally as the medical device is sending data I am just printing '.'

Now I will reverse the booleans to have it connect to the iPhone first.

// Case #1 - connect to medical device first then iPhone
// volatile bool shouldBeScanning = true;
// volatile bool shouldAdvertiseToIphone = false;

// Case #2 - connect to iPhone first then medical device
volatile bool shouldBeScanning = false;
volatile bool shouldAdvertiseToIphone = true;

Here is the output. As you can see once connected to the iPhone the attempt to connect to the medical device after a successful scan never succeeds.

02061 [hal.ble] TRACE: Going to stop the stack...
0000002389 [hal] INFO: WiFi off
0000002398 [system.nm] INFO: State changed: NONE -> DISABLED
0000002414 [system.nm] TRACE: Interface 4 power state: DOWN
0000002452 [comm] INFO: channel inited
0000002474 [hal] INFO: rltk_wlan_set_netif_info: 0, 94:94:4a:04:08:38
0000002621 [hal] INFO: WiFi on
advertising...
advertising...
advertising...
advertising...
advertising...
advertising...
advertising...
advertising...
advertisConnected to phone with address 53:74:48:69:0D:C9
0000003299 [wiring.ble] TRACE: Connected
ing...
0000003353 [system.ctrl.ble] TRACE: Connected
got time
scanning for medical device...
found medical device, attempting to connect to 94:94:4A:04:C1:35 ...
scanning for medical device...
found medical device, attempting to connect to 94:94:4A:04:C1:35 ...
scanning for medical device...
found medical device, attempting to connect to 94:94:4A:04:C1:35 ...
scanning for medical device...
found medical device, attempting to connect to 94:94:4A:04:C1:35 ...
scanning for medical device...

Any ideas as to why or if I am doing something wrong?

@rickkas7 can I get support to look at this?

Hi @iitgrad, this PR should fix the issue: [Gen4] ble: clear connecting flag on connected for peripheral role by XuGuohui · Pull Request #2839 · particle-iot/device-os · GitHub

3 Likes

Thank you @ielec. Hooray!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.