BLE Subscribe Help

I would like to port this code that I use successfully on an ESP32-S3 to the Nano Matter...

#include <ArduinoBLE.h>

uint8_t probeStatusData[50] = {};
bool CPTscanning = false;

void setup() {
  Serial.begin(9600);
  Serial.print(millis());
  Serial.println(" - here we go...");

  BLE.begin();
  BLE.setEventHandler(BLEDiscovered, CPTscanned);
}

void loop() {
  if (!CPTscanning) {
    Serial.println("Scanning...");
    BLE.scanForAddress("xx:xx:xx:xx:xx:xx");  // Enter CPT MAC Address Here
    CPTscanning = true;
  }
  BLE.poll();
  delay(10);
}

void CPTscanned(BLEDevice CPTprobe) {
  BLE.stopScan();
  Serial.println("CPT Found");
  CPTscanning = false;

  if (!CPTprobe.connect()) {
    Serial.println("Returning...");
    return;
  }

  Serial.println("Connected");

  if (!CPTprobe.discoverService("00000100-caab-3792-3d44-97ae51c1407a")) {
    Serial.println("Returning...");
    CPTprobe.disconnect();
    return;
  }

  Serial.println("Discovered");

  BLEService CPTservice = CPTprobe.service("00000100-caab-3792-3d44-97ae51c1407a");
  BLECharacteristic CPTcharacteristic = CPTservice.characteristic("00000101-caab-3792-3d44-97ae51c1407a");

  if (!CPTcharacteristic.subscribe()) {
    Serial.println("Returning...");
    CPTprobe.disconnect();
    return;
  }

  Serial.println("Subscribed!!!");

  while (CPTprobe.connected()) {
    if (CPTcharacteristic.valueUpdated()) {
      CPTcharacteristic.readValue(&probeStatusData, 50);

      if (!bitRead(probeStatusData[21], 0)) {  // Check for Normal vs. Instant Mode
        printData(probeStatusData, 50);
      } else {
        Serial.println("Instant Read");
      }
    }
  }
}

void printData(const unsigned char data[], int length) {
  Serial.print(millis());
  Serial.print(" - ");
  for (int i = 0; i < length; i++) {
    unsigned char c = data[i];
    if (c < 16) {
      Serial.print("0");
    }
    Serial.print(c, HEX);
  }
  Serial.println();
}

On the ESP32-S3 probe disconnects are handled very robustly, it just starts scanning again and reconnects and subscribes.

On the Nano Matter using the Arduino BLE stack, it doesn't recognize if the connection is lost...the while (CPTprobe.connected()) just doesn't seem to work.

I tried replacing the while (CPTprobe.connected()) with a Boolean, but it strangely only works for one disconnection...

#include <ArduinoBLE.h>

uint8_t probeStatusData[50] = {};
bool CPTscanning = false;
bool CPTsubscribed = false;

void setup() {
  delay(1000);
  Serial.begin(9600);
  delay(1000);
  Serial.print(millis());
  Serial.println(" - here we go...");

  if (!BLE.begin()) {
    Serial.println("BLE Not Started");
    while (1)
      ;
  }
  BLE.setEventHandler(BLEDiscovered, CPTscanned);
}

void loop() {
  if (!CPTscanning) {
    Serial.println("Scanning...");
    BLE.scanForAddress("xx:xx:xx:xx:xx:xx");  // Enter CPT MAC Address Here
    CPTscanning = true;
  }
  BLE.poll();
  delay(10);
}

void CPTscanned(BLEDevice CPTprobe) {
  BLE.stopScan();
  Serial.println("CPT Found");
  CPTscanning = false;

  if (!CPTprobe.connect()) {
    Serial.println("Returning...");
    return;
  }

  Serial.println("Connected");

  if (!CPTprobe.discoverService("00000100-caab-3792-3d44-97ae51c1407a")) {
    Serial.println("Returning...");
    CPTprobe.disconnect();
    return;
  }

  Serial.println("Discovered");

  BLEService CPTservice = CPTprobe.service("00000100-caab-3792-3d44-97ae51c1407a");
  BLECharacteristic CPTcharacteristic = CPTservice.characteristic("00000101-caab-3792-3d44-97ae51c1407a");

  if (!CPTcharacteristic.subscribe()) {
    Serial.println("Returning...");
    CPTprobe.disconnect();
    return;
  }

  CPTsubscribed = true;
  Serial.println("Subscribed!!!");

  while (CPTsubscribed) {
    if (CPTcharacteristic.valueUpdated()) {
      CPTcharacteristic.readValue(&probeStatusData, 50);
      printData(probeStatusData, 50);
    }
    if (!CPTprobe.connected()){
      CPTsubscribed = false;
      return;
    }
  }  
}

void printData(const unsigned char data[], int length) {
  Serial.print(millis());
  Serial.print(" - ");
  for (int i = 0; i < length; i++) {
    unsigned char c = data[i];
    if (c < 16) {
      Serial.print("0");
    }
    Serial.print(c, HEX);
  }
  Serial.println();
}

It reconnects and subscribes after the first disconnection, then just scans forever if the probe disconnects a second time.

I just can't figure out how to make recovery from disconnections (which can happen often) more robust on the Nano Matter.

I assume the Arduino BLE stack is correct for this.
If I try to compile with the SiLabs BLE stack I get the error...

fatal error: sl_hci_common_transport.h: No such file or directory
27 | #include "sl_hci_common_transport.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1

I tried to play with the the Silicon Labs BLE scan example sketch using the SiLabs BLE stack and I can figure out how to check for the MAC address and stop the scan...

void setup() {
  Serial.begin(9600);
}

void loop() {
  ;
}

void sl_bt_on_event(sl_bt_msg_t* evt) {
  sl_status_t sc;

  switch (SL_BT_MSG_ID(evt->header)) {
    // This event is received when the BLE device has successfully booted
    case sl_bt_evt_system_boot_id:
      // Print a welcome message
      Serial.begin(9600);
      Serial.println();
      Serial.println("Silicon Labs BLE scan example");
      Serial.println("BLE stack booted");
      // Start scanning for other BLE devices
      sc = sl_bt_scanner_set_parameters(sl_bt_scanner_scan_mode_active,  // mode
                                        16,                              // interval (value * 0.625 ms)
                                        16);                             // window (value * 0.625 ms)
      app_assert_status(sc);
      sc = sl_bt_scanner_start(sl_bt_scanner_scan_phy_1m,
                               sl_bt_scanner_discover_generic);
      app_assert_status(sc);
      Serial.println("Started scanning...");
      break;

    // This event is received when we scan the advertisement of another BLE device
    case sl_bt_evt_scanner_legacy_advertisement_report_id:

      if (evt->data.evt_scanner_legacy_advertisement_report.address.addr[5] == 0
          && evt->data.evt_scanner_legacy_advertisement_report.address.addr[4] == 0
          && evt->data.evt_scanner_legacy_advertisement_report.address.addr[3] == 0
          && evt->data.evt_scanner_legacy_advertisement_report.address.addr[2] == 0
          && evt->data.evt_scanner_legacy_advertisement_report.address.addr[1] == 0
          && evt->data.evt_scanner_legacy_advertisement_report.address.addr[0] == 0) {
        sc = sl_bt_scanner_stop();
        app_assert_status(sc);
        Serial.println("Found");
      }
      break;
  }
}

#ifndef BLE_STACK_SILABS
#error "This example is only compatible with the Silicon Labs BLE stack. Please select 'BLE (Silabs)' in 'Tools > Protocol stack'."
#endif

...but then can go no further as there are no examples that I can find of how how to use the SiLabs BLE stack to make the connection, discover the GATT service and then subscribe.
It seems like the SiLabs BLE stack would be the better way to go, but only for users with very advanced knowledge (not me).

I just need to subscribe to a known update service on a known MAC address and forward the 50 byte payload.

Thank you for any advice.

In case anyone else runs into a similar need, here is SiLabs BLE stack code that is working for my application...

uint8_t probeStatusData[50] = {};
bool fresh = false;

void setup() {
  Serial.begin(115200);  
  pinMode(LED_BUILTIN, OUTPUT);
  while(!Serial && millis() < 5000) {}
  digitalWrite(LED_BUILTIN, HIGH);
}

void loop() {
  if (fresh == true) {
    fresh = false;
    Serial.print(millis());
    Serial.print(" - ");
    for (int i = 0; i < 50; i++) {
      unsigned char c = probeStatusData[i];
      if (c < 16) {
        Serial.print("0");
      }
      Serial.print(c, HEX);
    }
    Serial.println();
  }
}

// ********************************
// Silicon Labs Bluetooth Stack
// ********************************
enum conn_state_t {
  ST_BOOT,
  ST_SCAN,
  ST_CONNECT,
  ST_SERVICE_DISCOVER,
  ST_CHAR_DISCOVER,
  ST_REQUEST_NOTIFICATION,
  ST_RECEIVE_DATA
};

const uint8_t target_mac[6] = { 0x6f, 0x5e, 0x4d, 0x3c, 0x2b, 0x1a };  // 1a:2b:3c:4d:5e:6f in reverse order

const uint8_t target_uuid[] = { 0x7A, 0x40, 0xC1, 0x51, 0xAE, 0x97, 0x44, 0x3D,
                                0x92, 0x37, 0xAB, 0xCA, 0x00, 0x01, 0x00, 0x00 };  // For 00000100-CAAB-3792-3D44-97AE51C1407A in little-endian

const uint8_t target_char_uuid[] = { 0x7A, 0x40, 0xC1, 0x51, 0xAE, 0x97, 0x44, 0x3D,
                                     0x92, 0x37, 0xAB, 0xCA, 0x01, 0x01, 0x00, 0x00 };  // For 00000101-CAAB-3792-3D44-97AE51C1407A in little-endian

uint32_t CPT_service_handle = __UINT32_MAX__;
uint16_t CPT_char_handle = __UINT16_MAX__;

uint8_t data_length = 50;

conn_state_t connection_state = ST_BOOT;

// Bluetooth Stack Event Handler
void sl_bt_on_event(sl_bt_msg_t *evt) {
  sl_status_t sc;

  switch (SL_BT_MSG_ID(evt->header)) {
    // This event is received when BLE has successfully booted
    case sl_bt_evt_system_boot_id:
      // Start scanning for BLE devices
      sc = sl_bt_scanner_set_parameters(sl_bt_scanner_scan_mode_active, 16, 16);
      app_assert_status(sc);

      sc = sl_bt_scanner_start(sl_bt_scanner_scan_phy_1m,
                               sl_bt_scanner_discover_generic);
      app_assert_status(sc);
      connection_state = ST_SCAN;
      break;

      // This event is received when a BLE device is scanned
    case sl_bt_evt_scanner_legacy_advertisement_report_id:
      // Check if the BLE device is our CPT MAC address
      if (memcmp(evt->data.evt_scanner_legacy_advertisement_report.address.addr, target_mac, 6) == 0) {
        // Stop scanning
        sc = sl_bt_scanner_stop();
        app_assert_status(sc);
        // Connect to the device
        sc = sl_bt_connection_open(evt->data.evt_scanner_legacy_advertisement_report.address,
                                   evt->data.evt_scanner_legacy_advertisement_report.address_type,
                                   sl_bt_gap_phy_1m,
                                   NULL);
        app_assert_status(sc);
        connection_state = ST_CONNECT;
      }
      break;

    // This event is received when a BLE connection has been opened
    case sl_bt_evt_connection_opened_id:
      // Discover the target Probe Status service
      sc = sl_bt_gatt_discover_primary_services_by_uuid(evt->data.evt_connection_opened.connection,
                                                        sizeof(target_uuid),
                                                        target_uuid);
      app_assert_status(sc);
      connection_state = ST_SERVICE_DISCOVER;
      break;

    // This event is received when a BLE connection has been closed
    case sl_bt_evt_connection_closed_id:
      // Restart scanning
      sc = sl_bt_scanner_start(sl_bt_scanner_scan_phy_1m,
                               sl_bt_scanner_discover_generic);
      app_assert_status(sc);
      connection_state = ST_SCAN;
      break;

    // This event is generated when the target service is discovered
    case sl_bt_evt_gatt_service_id:
      // Store the handle of the discovered service
      CPT_service_handle = evt->data.evt_gatt_service.service;
      break;

    // This event is generated when the target characteristic is discovered
    case sl_bt_evt_gatt_characteristic_id:
        // Store the handle of the discovered characteristic
      CPT_char_handle = evt->data.evt_gatt_characteristic.characteristic;
      break;

    // This event is received when the GATT procedure completes
    case sl_bt_evt_gatt_procedure_completed_id:

      if (connection_state == ST_SERVICE_DISCOVER) {
        // Discover target characteristic on the CPT
        sc = sl_bt_gatt_discover_characteristics_by_uuid(evt->data.evt_gatt_procedure_completed.connection,
                                                         CPT_service_handle,
                                                         sizeof(target_char_uuid),
                                                         target_char_uuid);
        app_assert_status(sc);
        connection_state = ST_CHAR_DISCOVER;
        break;
      }

      if (connection_state == ST_CHAR_DISCOVER) {
        // Enable update notifications
        sc = sl_bt_gatt_set_characteristic_notification(evt->data.evt_gatt_procedure_completed.connection,
                                                        CPT_char_handle,
                                                        sl_bt_gatt_notification);
        app_assert_status(sc);
        connection_state = ST_REQUEST_NOTIFICATION;
        break;
      }

      if (connection_state == ST_REQUEST_NOTIFICATION) {
        // Subscribed to notifications
        connection_state = ST_RECEIVE_DATA;
      }
      break;

    // This event is received when the characteristic value ia updated
    case sl_bt_evt_gatt_characteristic_value_id:
      // Check if this is a notification
      if (evt->data.evt_gatt_characteristic_value.att_opcode == sl_bt_gatt_handle_value_notification) {
        // Check if this is from our target characteristic
        if (evt->data.evt_gatt_characteristic_value.characteristic == CPT_char_handle) {
          // Read the Probe Status data
          data_length = evt->data.evt_gatt_characteristic_value.value.len;
          memcpy(probeStatusData,
                 evt->data.evt_gatt_characteristic_value.value.data,
                 data_length);
          fresh = true;
        }
      }
      break;

    // Default event handler
    default:
      break;
  }
}

#ifndef BLE_STACK_SILABS
#error "This example is only compatible with the Silicon Labs BLE stack. Please select 'BLE (Silabs)' in 'Tools > Protocol stack'."
#endif