espressif/arduino-esp32

BLE server notify() sent before onWrite() client ack in 3.3.0+ (Nimble v. Bluedroid difference)

Closed this issue · 9 comments

Board

esp32-c6-devkitC, esp32-s3-zero

Device Description

DevkitC powered over usbc via jtag connector. S3-zero powered over usbc connector.

Hardware Configuration

Nothing else attached

Version

v3.3.2

Type

Bug

IDE Name

Arduino IDE

Operating System

MacOS 26.0.1

Flash frequency

QIO 80Mhz

PSRAM enabled

no

Upload speed

115200

Description

The attached sketch is a minimalist BLE server, when compiled against v3.2.1 (Bluedroid default), the server receives a write to initiate a client handshake, server acknowledges write and then notifies the client with a success message to complete the handshake. But when compiled against v3.3.2 (Nimble default), the notify happens before the write acknowledge and this causes the client handshake to fail because the notify-response timestamp is earlier than (or the same as) the write-request timestamp.

Note: I am calling notify() from the onWrite() callback which is possibly not a good practice given the call chain, but this code worked fine for the client when compiled with Bluedroid but failed silently when compilied with Nimble. For anyone being migrated from Bluedroid to Nimble via esp32 arduino core, this lack of backwards compatibility wastes a lot of time (as it did mine).

At issue here is that Bluedroid write acknowldge/notify timing is different from Nimble. I should get a warning that calling notify() from within onWrite() is not a good idea, or the timing of how this is handled should be the same as Bluedroid. Possibly both.

Sketch

#include <BLEDevice.h>
#include <BLE2902.h>

BLEServer* pServer = nullptr;
BLECharacteristic* pTxCharacteristic = nullptr;
BLECharacteristic* pRxCharacteristic = nullptr;

class MyServerCallbacks : public BLEServerCallbacks {
  /* esp32 v3.3.0 Nimble format */
  // void onConnect(BLEServer* pServer, ble_gap_conn_desc *param) override {
  //   pServer->updateConnParams(param->conn_handle, 12, 24, 4, 500);
  // }
  /* esp32 v3.2.1 Bluedroid format */
  void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) override {
    pServer->updateConnParams(param->connect.remote_bda, 12, 24, 4, 500);
  }
  void onDisconnect(BLEServer* pServer) override {
    pServer->getAdvertising()->start();
  }
};

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) override {
    String rxValue = String(pCharacteristic->getValue().c_str());
    Serial.print("BLE Write: "); Serial.println(rxValue);
    if (rxValue == "CHAN;2100\n") {
      pTxCharacteristic->setValue("# Active channels set to 2100\n");
      pTxCharacteristic->notify();
    } else {
      pTxCharacteristic->setValue("0,0,0,0,0\n");
      pTxCharacteristic->notify();
    }
  }
};

void setup() {
  Serial.begin(115200);

  BLEDevice::init("ESP32_Skycommand_BLE");

  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService* pService = pServer->createService("6e400001-b5a3-f393-e0a9-e50e24dcca9e");

  pTxCharacteristic = pService->createCharacteristic("6e400003-b5a3-f393-e0a9-e50e24dcca9e",
        BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ
    );
  pTxCharacteristic->addDescriptor(new BLE2902());

  pRxCharacteristic = pService->createCharacteristic("6e400002-b5a3-f393-e0a9-e50e24dcca9e",
        BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR
    );
  pRxCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising* pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  // callbacks do all the work
}

Debug Message

Following are detailed logs from the Android app nRF Connect from Nordic Semi
-----------------------------------------------------------------------
nRF Connect (magnmci: Nimble v3.3.2), 2025-10-22
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V	09:21:19.688	Connecting to F0:F5:BD:02:A8:9A...
D	09:21:19.688	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	09:21:19.816	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	09:21:19.816	Connected to F0:F5:BD:02:A8:9A
V	09:21:19.834	Discovering services...
D	09:21:19.834	gatt.discoverServices()
D	09:21:19.835	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
I	09:21:19.996	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I	09:21:20.526	Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D	09:21:20.832	[Callback] Services discovered with status: 0
I	09:21:20.832	Services discovered
V	09:21:20.838	Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D	09:21:20.838	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	09:21:20.842	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I	09:21:21.047	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V	09:21:23.862	Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D	09:21:23.862	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D	09:21:23.863	gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I	09:21:23.925	Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A	09:21:23.925	"Notifications enabled" sent
V	09:21:23.928	Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V	09:21:41.149	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:21:41.149	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B32313030)
I	09:21:41.236	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:21:41.236	"# Active channels se" received
I	09:21:41.236	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30, "CHAN;2100"
A	09:21:41.237	"CHAN;2100" sent
[ magnmci: note the write acknowledge occurs AFTER the notification is sent ]
----------------------------------------------------------
nRF Connect (magnmci: Bluedroid v3.2.1), 2025-10-22
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V	09:29:41.770	Connecting to F0:F5:BD:02:A8:9A...
D	09:29:41.770	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	09:29:41.975	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	09:29:41.975	Connected to F0:F5:BD:02:A8:9A
D	09:29:41.975	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
V	09:29:41.976	Discovering services...
D	09:29:41.976	gatt.discoverServices()
I	09:29:42.144	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I	09:29:42.580	Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D	09:29:42.984	[Callback] Services discovered with status: 0
I	09:29:42.985	Services discovered
V	09:29:42.993	Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
- Central Address Resolution [R] (0x2AA6)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D	09:29:42.993	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	09:29:42.997	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I	09:29:43.198	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V	09:29:45.558	Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D	09:29:45.558	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D	09:29:45.560	gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I	09:29:45.627	Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A	09:29:45.627	"Notifications enabled" sent
V	09:29:45.632	Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V	09:29:55.329	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:29:55.329	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B32313030)
I	09:29:55.439	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30, "CHAN;2100"
A	09:29:55.439	"CHAN;2100" sent
I	09:29:55.442	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:29:55.442	"# Active channels se" received
[magnmci: note the write acknowledge occurs before the notification is sent]

Other Steps to Reproduce

You can see the timing differences using nRF Connect for Android - logs included in debug. The timing issue can be seen in the last 5 lines of each.

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

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

This sketch moves the notify OUTSIDE of onWrite() to be handled in loop, but the timing issue remained until the delay was added:

#include <BLEDevice.h>
#include <BLE2902.h>

BLEServer* pServer = nullptr;
BLECharacteristic* pTxCharacteristic = nullptr;
BLECharacteristic* pRxCharacteristic = nullptr;

String pendingMessage = "";   // Holds last command written by client
bool notifyPending = false;   // True when we need to send a notification

class MyServerCallbacks : public BLEServerCallbacks {
  /* esp32 v3.3.0 Nimble format */
  void onConnect(BLEServer* pServer, ble_gap_conn_desc *param) override {
    pServer->updateConnParams(param->conn_handle, 12, 24, 4, 500);
  }
  /* esp32 v3.2.1 Bluedroid format */
  // void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) override {
  //   pServer->updateConnParams(param->connect.remote_bda, 12, 24, 4, 500);
  // }
  void onDisconnect(BLEServer* pServer) override {
    pServer->getAdvertising()->start();
  }
};

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic* pCharacteristic) override {
    String rxValue = String(pCharacteristic->getValue().c_str());
    Serial.print("BLE Write: "); Serial.println(rxValue);

    // Save the command for loop() to process
    pendingMessage = rxValue;
    notifyPending = true;  // flag for loop()
  }
};

void setup() {
  Serial.begin(115200);

  BLEDevice::init("ESP32_Skycommand_BLE");

  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService* pService = pServer->createService("6e400001-b5a3-f393-e0a9-e50e24dcca9e");

  pTxCharacteristic = pService->createCharacteristic("6e400003-b5a3-f393-e0a9-e50e24dcca9e",
        BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ
    );
  pTxCharacteristic->addDescriptor(new BLE2902());

  pRxCharacteristic = pService->createCharacteristic("6e400002-b5a3-f393-e0a9-e50e24dcca9e",
        BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR
    );
  pRxCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();

  BLEAdvertising* pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  if (notifyPending) {
    // delay(100);
    notifyPending = false;  // consume the flag

    if (pendingMessage == "CHAN;2100\n") {
      Serial.print("BLE notify 2100");
      pTxCharacteristic->setValue("# Active channels set to 2100\n");
    } else {
      pTxCharacteristic->setValue("0,0,0,0,0\n");
    }
    pTxCharacteristic->notify();
  }
}

And here we show the nRF Connect log with the above code, no delay....the first write/notify interaction occurred in the correct order, the 2nd write/notify interaction was reversed which would have been a client handshake failure.

nRF Connect, 2025-10-23
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V	08:00:40.595	Connecting to F0:F5:BD:02:A8:9A...
D	08:00:40.595	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	08:00:40.728	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	08:00:40.728	Connected to F0:F5:BD:02:A8:9A
V	08:00:40.745	Discovering services...
D	08:00:40.745	gatt.discoverServices()
D	08:00:40.746	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
I	08:00:40.876	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I	08:00:41.426	Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D	08:00:41.750	[Callback] Services discovered with status: 0
I	08:00:41.750	Services discovered
V	08:00:41.751	Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D	08:00:41.751	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	08:00:41.752	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I	08:00:41.950	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V	08:00:46.887	Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D	08:00:46.887	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D	08:00:46.890	gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I	08:00:47.081	Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A	08:00:47.081	"Notifications enabled" sent
V	08:00:47.088	Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V	08:00:59.175	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	08:00:59.175	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	08:00:59.288	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	08:00:59.288	"CHAN;2100
" sent
I	08:00:59.293	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	08:00:59.293	"# Active channels se" received
V	08:02:06.054	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	08:02:06.054	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	08:02:06.191	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	08:02:06.192	"# Active channels se" received
I	08:02:06.201	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	08:02:06.201	"CHAN;2100
" sent

Could you please test if #11948 solves your issue. Tested locally and it seems to solve the race condition.

Tested with this PR and I still see the problem...

Local environment...

MacBookPro:esp32 chris$ pwd
/Users/chris/development/Arduino/hardware/espressif/esp32
MacBookPro:esp32 chris$ git status
On branch pr-11948
nothing to commit, working tree clean

Arduino IDE Build...

FQBN: espressif:esp32:esp32c6:CDCOnBoot=cdc,DebugLevel=debug
Using board 'esp32c6' from platform in folder: /Users/chris/development/Arduino/hardware/espressif/esp32
Using core 'esp32' from platform in folder: /Users/chris/development/Arduino/hardware/espressif/esp32

The client handshake protocol is:

  1. client writes "CHAN;2100\n"
  2. server acks the write
  3. server notifies client with "# Active channels se"([t to 2100\n])

I've hilighted below ('>') two (out of 4) exchanges in the nrfConnect log where instead of 1.2.3 above the sequence appears to be 1.3.2....

nRF Connect, 2025-10-25
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V	09:25:42.768	Connecting to F0:F5:BD:02:A8:9A...
D	09:25:42.768	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	09:25:42.923	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	09:25:42.923	Connected to F0:F5:BD:02:A8:9A
D	09:25:42.923	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
V	09:25:42.924	Discovering services...
D	09:25:42.924	gatt.discoverServices()
I	09:25:43.110	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I	09:25:43.656	Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D	09:25:43.973	[Callback] Services discovered with status: 0
I	09:25:43.973	Services discovered
V	09:25:43.975	Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D	09:25:43.975	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	09:25:43.977	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I	09:25:44.190	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V	09:25:46.677	Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D	09:25:46.677	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D	09:25:46.679	gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I	09:25:46.768	Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A	09:25:46.768	"Notifications enabled" sent
V	09:25:46.774	Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
> V	09:25:56.686	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
> D	09:25:56.686	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
> I	09:25:56.728	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
> A	09:25:56.728	"# Active channels se" received
> I	09:25:56.729	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
> A	09:25:56.729	"CHAN;2100
> " sent
V	09:26:28.113	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:26:28.113	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	09:26:28.258	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	09:26:28.263	"CHAN;2100
" sent
I	09:26:28.264	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:26:28.264	"# Active channels se" received
V	09:26:37.809	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:26:37.809	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	09:26:37.887	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	09:26:37.887	"CHAN;2100
" sent
I	09:26:37.888	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:26:37.888	"# Active channels se" received
V	09:26:47.515	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:26:47.515	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	09:26:47.700	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	09:26:47.700	"CHAN;2100
" sent
I	09:26:47.703	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:26:47.703	"# Active channels se" received
> V	09:27:17.198	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
> D	09:27:17.198	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
> I	09:27:17.344	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
> A	09:27:17.344	"# Active channels se" received
> I	09:27:17.346	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
> A	09:27:17.346	"CHAN;2100
> " sent

Serial debug log for the same session...to my eye, these logs appear to show something different than what the nrf connect app (test client) saw above...

09:25:19.606 -> =========== Before Setup Start ===========
09:25:19.606 -> Chip Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->   Model             : ESP32-C6
09:25:19.606 ->   Package           : 0
09:25:19.606 ->   Revision          : 0.01
09:25:19.606 ->   Cores             : 1
09:25:19.606 ->   CPU Frequency     : 160 MHz
09:25:19.606 ->   XTAL Frequency    : 4atures Bitfield : 0x00000052
09:25:19.606 ->   Embedded Flash    : No
09:25:19.606 ->   Embedded PSRAM    : No
09:25:19.606 ->   2.4GHz WiFi       : Yes
09:25:19.606 ->   Classic BT        : No
09:25:19.606 ->   BT Low Energy     : Yes
09:25:19.606 ->   IEEE 802.15.4     : Yes
09:25:19.606 -> ------------------------------------------
09:25:19.606 -> INTERNAL Memory Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->   Total Size        :   427228 B ( 417.2 KB)
09:25:19.606 ->   Free Bytes        :   392860 B ( 383.7 KB)
09:25:19.606 ->   Allocated Bytes   :    27832 B (  27.2 KB)
09:25:19.606 ->   Minimum Free Bytes:   387872 B ( 378.8 KB)
09:25:19.606 ->   Largest Free Block:   368628 B ( 360.0 KB)
09:25:19.606 -> ------------------------------------------
09:25:19.606 -> Flash Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->   Chip Size         :  8388608 B (8 MB)
09:25:19.606 ->   Block Size        :    65536 B (  64.0 KB)
09:25:19.606 ->   Sector Size       :     4096 B (   4.0 KB)
09:25:19.606 ->   Page Size         :      256 B (   0.2 KB)
09:25:19.606 ->   Bus Speed         : 80 MHz
09:25:19.606 ->   Flash Frequency   : 80 MHz (source: 80 MHz, divider: 1)
09:25:19.606 ->   Bus Mode          : QIO
09:25:19.606 -> ------------------------------------------
09:25:19.606 -> Partitions Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->                 nvs : addr: 0x00009000, size:    20.0 KB, type: DATA, subtype: NVS
09:25:19.606 ->             otadata : addr: 0x0000E000, size:     8.0 KB, type: DATA, subtype: OTA
09:25:19.606 ->                app0 : addr: 0x00010000, size:  1280.0 KB, type:  APP, subtype: OTA_0
09:25:19.606 ->                app1 : addr: 0x00150000, size:  1280.0 KB, type:  APP, subtype: OTA_1
09:25:19.606 ->              spiffs : addr: 0x00290000, size:  1408.0 KB, type: DATA, subtype: SPIFFS
09:25:19.606 ->            coredump : addr: 0x003F0000, size:    64.0 KB, type: DATA, subtype: COREDUMP
09:25:19.606 -> ------------------------------------------
09:25:19.606 -> Software Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->   Compile Date/Time : Oct 25 2025 09:07:58
09:25:19.606 ->   Compile Host OS   : macosx
09:25:19.606 ->   ESP-IDF Version   : v5.5.1-255-g07e9bf4970
09:25:19.606 ->   Arduino Version   : 3.3.2
09:25:19.606 -> ------------------------------------------
09:25:19.606 -> Board Info:
09:25:19.606 -> ------------------------------------------
09:25:19.606 ->   Arduino Board     : ESP32C6_DEV
09:25:19.606 ->   Arduino Variant   : esp32c6
09:25:19.606 ->   Arduino FQBN      : espressif:esp32:esp32c6:UploadSpeed=921600,CDCOnBoot=cdc,CPUFreq=160,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=debug,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default
09:25:19.606 -> ============ Before Setup End ============
09:25:19.666 -> [  1136][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 12 already has type USB_DM (38) with bus 0x40818008
09:25:19.666 -> [  1136][I][esp32-hal-periman.c:141] perimanSetPinBus(): Pin 13 already has type USB_DP (39) with bus 0x40818008
09:25:19.666 -> [  1137][I][BLEDevice.cpp:246] init(): Initializing BLE stack: NimBLE
09:25:19.731 -> [  1210][I][BLEDevice.cpp:1237] host_task(): NimBLE host task started
09:25:19.731 -> [  1213][D][BLEDevice.cpp:1259] onSync(): onSync
09:25:19.945 -> [  1415][D][BLEService.cpp:238] addCharacteristic(): Adding characteristic: uuid=6e400003-b5a3-f393-e0a9-e50e24dcca9e to service: UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e, handle: 0xffff
09:25:19.945 -> [  1416][I][BLECharacteristic.cpp:109] addDescriptor(): NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it.
09:25:19.945 -> You should check the characteristic properties for notification or indication rather than adding the descriptor manually.
09:25:19.945 -> This will be removed in a future version of the library.
09:25:19.945 -> [  1418][D][BLEService.cpp:238] addCharacteristic(): Adding characteristic: uuid=6e400002-b5a3-f393-e0a9-e50e24dcca9e to service: UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e, handle: 0xffff
09:25:19.945 -> [  1419][D][BLEService.cpp:511] start(): >> start(): Starting service: UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e, handle: 0xffff
09:25:19.945 -> [  1420][D][BLEService.cpp:557] start(): Adding 2 characteristics for service UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e, handle: 0xffff
09:25:19.945 -> [  1421][D][BLEService.cpp:587] start(): Adding 0 descriptors for characteristic 6e400003-b5a3-f393-e0a9-e50e24dcca9e
09:25:19.945 -> [  1422][D][BLEService.cpp:587] start(): Adding 0 descriptors for characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
09:25:19.945 -> [  1422][D][BLEService.cpp:645] start(): << start()
09:25:19.945 -> [  1423][I][BLEDevice.cpp:790] getAdvertising(): create advertising
09:25:19.945 -> [  1423][D][BLEDevice.cpp:792] getAdvertising(): get advertising
09:25:19.945 -> primary service
09:25:19.945 ->            uuid 0x1800
09:25:19.945 ->          handle 1
09:25:19.945 ->      end_handle 5
09:25:19.945 -> characteristic
09:25:19.945 ->            uuid 0x2a00
09:25:19.945 ->      def_handle 2
09:25:19.945 ->      val_handle 3
09:25:19.945 ->    min_key_size 0
09:25:19.977 ->           flags [READ]
09:25:19.977 -> characteristic
09:25:19.977 ->            uuid 0x2a01
09:25:19.977 ->      def_handle 4
09:25:19.977 ->      val_handle 5
09:25:19.977 ->    min_key_size 0
09:25:19.977 ->           flags [READ]
09:25:19.977 -> primary service
09:25:19.977 ->            uuid 0x1801
09:25:19.977 ->          handle 6
09:25:19.977 ->      end_handle 13
09:25:19.977 -> characteristic
09:25:19.977 ->            uuid 0x2a05
09:25:19.977 ->      def_handle 7
09:25:19.977 ->      val_handle 8
09:25:19.977 ->    min_key_size 0
09:25:19.977 ->           flags [INDICATE]
09:25:19.977 -> ccc descriptor
09:25:20.010 ->            uuid 0x2902
09:25:20.010 ->          handle 9
09:25:20.010 ->    min_key_size 0
09:25:20.010 ->           flags [READ|WRITE]
09:25:20.010 -> characteristic
09:25:20.010 ->            uuid 0x2b3a
09:25:20.010 ->      def_handle 10
09:25:20.010 ->      val_handle 11
09:25:20.010 ->    min_key_size 0
09:25:20.010 ->           flags [READ]
09:25:20.010 -> characteristic
09:25:20.010 ->            uuid 0x2b29
09:25:20.010 ->      def_handle 12
09:25:20.010 ->      val_handle 13
09:25:20.010 ->    min_key_size 0
09:25:20.010 ->           flags [READ|WRITE]
09:25:20.010 -> primary service
09:25:20.043 ->            uuid 6e400001-b5a3-f393-e0a9-e50e24dcca9e
09:25:20.043 ->          handle 14
09:25:20.043 ->      end_handle 19
09:25:20.043 -> characteristic
09:25:20.043 ->            uuid 6e400003-b5a3-f393-e0a9-e50e24dcca9e
09:25:20.043 ->      def_handle 15
09:25:20.043 ->      val_handle 16
09:25:20.043 ->    min_key_size 0
09:25:20.043 ->           flags [READ|NOTIFY]
09:25:20.043 -> ccc descriptor
09:25:20.043 ->            uuid 0x2902
09:25:20.043 ->          handle 17
09:25:20.043 ->    min_key_size 0
09:25:20.043 ->           flags [READ|WRITE]
09:25:20.043 -> characteristic
09:25:20.075 ->            uuid 6e400002-b5a3-f393-e0a9-e50e24dcca9e
09:25:20.075 ->      def_handle 18
09:25:20.075 ->      val_handle 19
09:25:20.075 ->    min_key_size 0
09:25:20.075 ->           flags [WRITE_NO_RSP|WRITE]
09:25:20.075 -> [  1538][D][BLEAdvertising.cpp:1404] start(): << Advertising start
09:25:20.075 -> =========== After Setup Start ============
09:25:20.075 -> INTERNAL Memory Info:
09:25:20.075 -> ------------------------------------------
09:25:20.075 ->   Total Size        :   427228 B ( 417.2 KB)
09:25:20.075 ->   Free Bytes        :   356696 B ( 348.3 KB)
09:25:20.075 ->   Allocated Bytes   :    60412 B (  59.0 KB)
09:25:20.075 ->   Minimum Free Bytes:   356608 B ( 348.2 KB)
09:25:20.075 ->   Largest Free Block:   335860 B ( 328.0 KB)
09:25:20.075 -> ------------------------------------------
09:25:20.075 -> GPIO Info:
09:25:20.075 -> ------------------------------------------
09:25:20.075 ->   GPIO : BUS_TYPE[bus/unit][chan]
09:25:20.075 ->   --------------------------------------  
09:25:20.075 ->     12 : USB_DM
09:25:20.075 ->     13 : USB_DP
09:25:20.075 ->     16 : UART_TX[0]
09:25:20.075 ->     17 : UART_RX[0]
09:25:20.075 -> ============ After Setup End =============
09:25:31.461 -> [ 12937][D][BLEServer.cpp:311] onConnect(): BLEServerCallbacks
09:25:31.461 -> [ 12938][D][BLEServer.cpp:312] onConnect(): BLEServerCallbacks
09:25:31.461 -> [ 12938][D][BLEServer.cpp:313] onConnect(): BLEServerCallbacks
09:25:31.461 -> [ 12939][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:31.659 -> [ 13128][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:31.691 -> [ 13159][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:31.691 -> [ 13160][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:32.087 -> [ 13562][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:32.383 -> [ 13842][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:32.546 -> [ 14027][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:36.508 -> [ 17958][D][BLEDevice.cpp:792] getAdvertising(): get advertising
09:25:36.508 -> [ 17959][D][BLEAdvertising.cpp:1404] start(): << Advertising start
09:25:36.508 -> [ 17959][D][BLEServer.cpp:1037] onDisconnect(): BLEServerCallbacks
09:25:36.508 -> [ 17960][D][BLEServer.cpp:1038] onDisconnect(): BLEServerCallbacks
09:25:36.508 -> [ 17960][D][BLEServer.cpp:1039] onDisconnect(): BLEServerCallbacks
09:25:36.508 -> [ 17960][D][BLESecurity.cpp:194] resetSecurity(): resetSecurity: Resetting security state
09:25:41.044 -> [ 22500][D][BLEServer.cpp:311] onConnect(): BLEServerCallbacks
09:25:41.044 -> [ 22500][D][BLEServer.cpp:312] onConnect(): BLEServerCallbacks
09:25:41.044 -> [ 22501][D][BLEServer.cpp:313] onConnect(): BLEServerCallbacks
09:25:41.044 -> [ 22501][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:41.178 -> [ 22650][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:41.244 -> [ 22700][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:41.376 -> [ 22848][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:41.771 -> [ 23244][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:42.135 -> [ 23583][D][BLEServer.cpp:953] handleGATTServerEvent(): << handleGATTServerEvent
09:25:42.299 -> [ 23778][D][BLEServer.cpp:788] handleGATTServerEvent(): Connection parameters updated.
09:25:44.872 -> [ 26328][I][BLEServer.cpp:698] handleGATTServerEvent(): subscribe event; attr_handle=16, subscribed: true
09:25:44.872 -> [ 26329][I][BLECharacteristic.cpp:1000] setSubscribe(): New subscribe value for conn: 0 val: 1
09:25:44.872 -> [ 26329][D][BLECharacteristic.cpp:1311] onSubscribe(): >> onSubscribe: default
09:25:44.872 -> [ 26330][D][BLECharacteristic.cpp:1312] onSubscribe(): << onSubscribe
09:25:54.814 -> [ 36288][D][BLECharacteristic.cpp:913] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:25:54.814 -> BLE Write: CHAN;2100
09:25:54.814 -> 
09:25:54.814 -> BLE notify 2100[ 36290][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:25:54.814 -> [ 36290][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:25:54.814 -> [ 36290][W][BLECharacteristic.cpp:1112] notify(): - Truncating to 20 bytes (maximum notify size)
09:25:54.814 -> [ 36291][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:25:54.814 -> [ 36292][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:25:54.814 -> [ 36292][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:25:54.814 -> [ 36292][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:26.363 -> [ 67818][D][BLECharacteristic.cpp:913] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:26:26.363 -> BLE Write: CHAN;2100
09:26:26.363 -> 
09:26:26.363 -> BLE notify 2100[ 67820][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:26:26.363 -> [ 67820][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:26:26.363 -> [ 67820][W][BLECharacteristic.cpp:1112] notify(): - Truncating to 20 bytes (maximum notify size)
09:26:26.363 -> [ 67821][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:26.363 -> [ 67821][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:26.363 -> [ 67822][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:26.363 -> [ 67822][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:35.981 -> [ 77448][D][BLECharacteristic.cpp:913] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:26:35.981 -> BLE Write: CHAN;2100
09:26:35.981 -> 
09:26:35.981 -> BLE notify 2100[ 77450][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:26:35.981 -> [ 77450][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:26:35.981 -> [ 77451][W][BLECharacteristic.cpp:1112] notify(): - Truncating to 20 bytes (maximum notify size)
09:26:35.981 -> [ 77451][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:35.981 -> [ 77452][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:35.981 -> [ 77452][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:35.981 -> [ 77452][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:45.795 -> [ 87258][D][BLECharacteristic.cpp:913] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:26:45.795 -> BLE Write: CHAN;2100
09:26:45.795 -> 
09:26:45.795 -> BLE notify 2100[ 87259][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:26:45.795 -> [ 87260][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:26:45.795 -> [ 87260][W][BLECharacteristic.cpp:1112] notify(): - Truncating to 20 bytes (maximum notify size)
09:26:45.795 -> [ 87261][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:45.795 -> [ 87261][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:26:45.795 -> [ 87261][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:26:45.795 -> [ 87262][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:27:15.440 -> [116899][D][BLECharacteristic.cpp:913] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:27:15.440 -> BLE Write: CHAN;2100
09:27:15.440 -> 
09:27:15.440 -> BLE notify 2100[116900][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:27:15.440 -> [116900][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:27:15.440 -> [116901][W][BLECharacteristic.cpp:1112] notify(): - Truncating to 20 bytes (maximum notify size)
09:27:15.440 -> [116901][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:27:15.440 -> [116902][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:27:15.440 -> [116902][D][BLECharacteristic.cpp:473] onStatus(): >> onStatus: default
09:27:15.440 -> [116902][D][BLECharacteristic.cpp:474] onStatus(): << onStatus
09:27:33.373 -> [134838][I][BLEServer.cpp:698] handleGATTServerEvent(): subscribe event; attr_handle=16, subscribed: false
09:27:33.373 -> [134839][I][BLECharacteristic.cpp:1000] setSubscribe(): New subscribe value for conn: 0 val: 0
09:27:33.373 -> [134839][D][BLECharacteristic.cpp:1311] onSubscribe(): >> onSubscribe: default
09:27:33.373 -> [134840][D][BLECharacteristic.cpp:1312] onSubscribe(): << onSubscribe
09:27:33.373 -> [134840][D][BLEDevice.cpp:792] getAdvertising(): get advertising
09:27:33.373 -> [134841][D][BLEAdvertising.cpp:1404] start(): << Advertising start
09:27:33.373 -> [134842][D][BLEServer.cpp:1037] onDisconnect(): BLEServerCallbacks
09:27:33.373 -> [134842][D][BLEServer.cpp:1038] onDisconnect(): BLEServerCallbacks
09:27:33.373 -> [134843][D][BLEServer.cpp:1039] onDisconnect(): BLEServerCallbacks
09:27:33.373 -> [134843][D][BLESecurity.cpp:194] resetSecurity(): resetSecurity: Resetting security state

Could you please pull the new changes and try again ? Modified the approach for the fix and it appears to work the same as bluedroid:

nRF Connect, 2025-10-27
ESP32_TimingTest (30:ED:A0:E4:5F:42)
V 13:46:42.630 Connecting to 30:ED:A0:E4:5F:42...
D 13:46:42.630 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D 13:46:42.963 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I 13:46:42.963 Connected to 30:ED:A0:E4:5F:42
V 13:46:42.965 Discovering services...
D 13:46:42.965 gatt.discoverServices()
D 13:46:42.973 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
I 13:46:43.391 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
D 13:46:43.549 [Callback] Services discovered with status: 0
I 13:46:43.549 Services discovered
V 13:46:43.552 Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D 13:46:43.552 gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D 13:46:43.553 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I 13:46:43.664 Connection parameters updated (interval: 30.0ms, latency: 0, timeout: 5000ms)
V 13:46:45.390 Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D 13:46:45.390 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D 13:46:45.392 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I 13:46:45.488 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A 13:46:45.488 "Notifications enabled" sent
V 13:46:45.493 Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V 13:46:49.952 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 13:46:49.952 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x74657374)
I 13:46:50.045 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 74-65-73-74, "test"
A 13:46:50.045 "test" sent
I 13:46:50.167 Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 41-43-4B-3A-74-65-73-74-3A-38-39-35-34-35, "ACK:test:89545"
A 13:46:50.167 "ACK:test:89545" received

Hi Lucas - I think I'm on the latest commit, but I'm afraid I'm still seeing the same issue.

Local environment...

MacBookPro:tools chris$ pwd
/Users/chris/development/Arduino/hardware/espressif/esp32/tools
MacBookPro:tools chris$ git log -1
commit 5c15f79fbb307f8c550afa351dcb6ad8128e9af8 (HEAD -> pr-11948)
Author: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com>
Date:   Mon Oct 27 13:44:28 2025 -0300

    fix(ble): Fix notification timing

Build process....


/usr/bin/env bash -c "[ ! -f \"/Users/chris/development/Arduino/sketch_oct21a\"/build_opt.h ] || cp -f \"/Users/chris/development/Arduino/sketch_oct21a\"/build_opt.h \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/build_opt.h"
/usr/bin/env bash -c "[ -f \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/build_opt.h ] || : > \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/build_opt.h"
/usr/bin/env bash -c ": > '/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/file_opts'"
/usr/bin/env bash -c "cp -f \"/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6\"/sdkconfig \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/sdkconfig"
Detecting libraries used...
/Users/chris/development/Arduino/hardware/espressif/esp32/tools/riscv32-esp-elf/bin/riscv32-esp-elf-g++ -c @/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6/flags/cpp_flags -w -Os -Werror=return-type -w -x c++ -E -CC -DF_CPU=160000000L -DARDUINO=10607 -DARDUINO_ESP32C6_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32C6_DEV" -DARDUINO_VARIANT="esp32c6" -DARDUINO_PARTITION_default -DARDUINO_HOST_OS="macosx" -DARDUINO_FQBN="espressif:esp32:esp32c6:UploadSpeed=921600,CDCOnBoot=cdc,CPUFreq=160,FlashFreq=80,FlashMode=qio,FlashSize=4M,PartitionScheme=default,DebugLevel=debug,EraseFlash=none,JTAGAdapter=default,ZigbeeMode=default" -DESP32=ESP32 -DCORE_DEBUG_LEVEL=4 -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 @/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6/flags/defines -I/Users/chris/development/Arduino/sketch_oct21a -iprefix /Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6/include/ @/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6/flags/includes -I/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6/qio_qspi/include -I/Users/chris/development/Arduino/hardware/espressif/esp32/cores/esp32 -I/Users/chris/development/Arduino/hardware/espressif/esp32/variants/esp32c6 @/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/build_opt.h @/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/file_opts /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch/sketch_oct21a.ino.cpp -o /dev/null
Alternatives for BLEDevice.h: [BLE@3.3.2]
ResolveLibrary(BLEDevice.h)
  -> candidates: [BLE@3.3.2]
[...]
Creating ESP32C6 image...
Merged 2 ELF sections.
Successfully created ESP32C6 image.
python3 /Users/chris/development/Arduino/hardware/espressif/esp32/tools/gen_esp32part.py -q /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/partitions.csv /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.partitions.bin
/usr/bin/env bash -c "[ ! -d \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/libraries/Insights ] || python3 \"/Users/chris/development/Arduino/hardware/espressif/esp32\"/tools/gen_insights_package.py /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F sketch_oct21a.ino \"/Users/chris/development/Arduino/sketch_oct21a\""
/usr/bin/env bash -c "[ ! -d \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/libraries/ESP_SR ] || [ ! -f \"/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6\"/esp_sr/srmodels.bin ] || cp -f \"/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esp32-arduino-libs/esp32c6\"/esp_sr/srmodels.bin \"/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F\"/srmodels.bin"
/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esptool/esptool --chip esp32c6 merge-bin -o /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.merged.bin --pad-to-size 4MB --flash-mode keep --flash-freq keep --flash-size keep 0x0 /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.bootloader.bin 0x8000 /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.partitions.bin 0xe000 /Users/chris/development/Arduino/hardware/espressif/esp32/tools/partitions/boot_app0.bin 0x10000 /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.bin
esptool v5.1.0
Wrote 0x400000 bytes to file '/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.merged.bin', ready to flash to offset 0x0.
Using library BLE at version 3.3.2 in folder: /Users/chris/development/Arduino/hardware/espressif/esp32/libraries/BLE 
/Users/chris/development/Arduino/hardware/espressif/esp32/tools/riscv32-esp-elf/bin/riscv32-esp-elf-size -A /Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.elf
Sketch uses 792782 bytes (60%) of program storage space. Maximum is 1310720 bytes.
Global variables use 23208 bytes (7%) of dynamic memory, leaving 304472 bytes for local variables. Maximum is 327680 bytes.
"/Users/chris/development/Arduino/hardware/espressif/esp32/tools/esptool/esptool" --chip esp32c6 --port "/dev/cu.usbmodem14201" --baud 921600  --before default-reset --after hard-reset write-flash  -z --flash-mode keep --flash-freq keep --flash-size keep 0x0 "/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.bootloader.bin" 0x8000 "/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.partitions.bin" 0xe000 "/Users/chris/development/Arduino/hardware/espressif/esp32/tools/partitions/boot_app0.bin" 0x10000 "/Users/chris/Library/Caches/arduino/sketches/38335E611514D814A2AA66B797AB009F/sketch_oct21a.ino.bin" 
esptool v5.1.0
Serial port /dev/cu.usbmodem14201:
Connecting...
Connected to ESP32-C6 on /dev/cu.usbmodem14201:
Chip type:          ESP32-C6 (QFN40) (revision v0.1)
Features:           Wi-Fi 6, BT 5 (LE), IEEE802.15.4, Single Core + LP Core, 160MHz
Crystal frequency:  40MHz
USB mode:           USB-Serial/JTAG
MAC:                f0:f5:bd:ff:fe:02:a8:98
BASE MAC:           f0:f5:bd:02:a8:98
MAC_EXT:            ff:fe

Uploading stub flasher...
Running stub flasher...
Stub flasher running.
Changing baud rate to 921600...
Changed.

Configuring flash size...
Flash will be erased from 0x00000000 to 0x00005fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000e000 to 0x0000ffff...
Flash will be erased from 0x00010000 to 0x000d1fff...
Compressed 21088 bytes to 13379...
[...]
Writing at 0x000d1940 [==============================] 100.0% 469115/469115 bytes... 
Wrote 792896 bytes (469115 compressed) at 0x00010000 in 4.9 seconds (1302.5 kbit/s).
Hash of data verified.

Hard resetting via RTS pin...

But I still see the sequence problem...

nRF Connect, 2025-10-27
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V 10:43:30.994 Connecting to F0:F5:BD:02:A8:9A...
D 10:43:30.994 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D 10:43:31.255 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
D 10:43:31.255 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
I 10:43:31.255 Connected to F0:F5:BD:02:A8:9A
V 10:43:31.264 Discovering services...
D 10:43:31.264 gatt.discoverServices()
I 10:43:31.377 Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I 10:43:31.886 Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D 10:43:32.116 [Callback] Services discovered with status: 0
I 10:43:32.116 Services discovered
V 10:43:32.123 Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D 10:43:32.124 gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D 10:43:32.126 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I 10:43:32.334 Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V 10:43:35.591 Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D 10:43:35.591 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D 10:43:35.593 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I 10:43:35.663 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A 10:43:35.663 "Notifications enabled" sent
V 10:43:35.667 Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V 10:43:52.009 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 10:43:52.009 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I 10:43:52.140 Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A 10:43:52.140 "# Active channels se" received
I 10:43:52.140 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A 10:43:52.140 "CHAN;2100
" sent
V 10:44:11.623 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 10:44:11.623 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I 10:44:11.694 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A 10:44:11.694 "CHAN;2100
" sent
I 10:44:11.694 Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A 10:44:11.694 "# Active channels se" received
V 10:44:23.954 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 10:44:23.954 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I 10:44:24.053 Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A 10:44:24.053 "# Active channels se" received
I 10:44:24.054 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A 10:44:24.054 "CHAN;2100
" sent

I don't want to waste your time, but I don't see a change on my end. Possibly I am doing it wrong?

I don't know what can be wrong as I can't reproduce this issue after my fix. I will try to make the task delay configurable to see if it might help you

I think that is best - I just modified local source just to be 100% sure my build is using the PR and it is. If I can control the delay safely, I can increase it until the problem stops - it is only a few ms - I just don't want to insert a delay() to halt the entire stack. Thanks for looking at this.

I added a delay based on the connection interval to make sure it is transmitted before sending the deferred notifications. Could you please test it again?

nRF Connect, 2025-10-28
ESP32-BLE-TEST-1 (40:4C:CA:42:6D:72)
V 12:27:17.970 Connecting to 40:4C:CA:42:6D:72...
D 12:27:17.970 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D 12:27:18.167 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I 12:27:18.167 Connected to 40:4C:CA:42:6D:72
V 12:27:18.174 Discovering services...
D 12:27:18.174 gatt.discoverServices()
D 12:27:18.176 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
I 12:27:18.450 Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
D 12:27:19.302 [Callback] Services discovered with status: 0
I 12:27:19.302 Services discovered
V 12:27:19.305 Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D 12:27:19.305 gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D 12:27:19.308 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I 12:27:19.413 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
V 12:27:33.809 Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D 12:27:33.809 gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D 12:27:33.813 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I 12:27:33.883 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A 12:27:33.883 "Notifications enabled" sent
V 12:27:33.888 Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V 12:27:49.885 Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D 12:27:49.885 gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B32313030)
I 12:27:49.971 Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30, "CHAN;2100"
A 12:27:49.971 "CHAN;2100" sent
I 12:27:50.127 Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A 12:27:50.127 "# Active channels se" received

Yes! This is working nicely with both the nRF Connect app, and with my fussy BLE client (Flutter Blue Plus on iOS). Thank you!

09:16:54.684 -> [215613][D][BLECharacteristic.cpp:959] handleGATTServerEvent(): Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e Write event
09:16:54.684 -> [215614][V][BLECharacteristic.cpp:353] setValue(): >> setValue: length=5, data=524541440a, characteristic UUID=6e400002-b5a3-f393-e0a9-e50e24dcca9e
09:16:54.717 -> [215615][V][FreeRTOS.cpp:179] take(): Semaphore taking: name: SetValue (0x408280b8), owner: <N/A> for <Unknown>
09:16:54.717 -> [215616][V][FreeRTOS.cpp:188] take(): Semaphore taken:  name: SetValue (0x408280b8), owner: <Unknown>
09:16:54.717 -> [215616][V][FreeRTOS.cpp:136] give(): Semaphore giving: name: SetValue (0x408280b8), owner: <Unknown>
09:16:54.717 -> [215617][V][BLECharacteristic.cpp:363] setValue(): << setValue
09:16:54.717 -> [215617][V][BLECharacteristic.cpp:934] processDeferredWriteCallback(): Deferring write callback by 35ms (conn_interval=24 units, 30ms)
09:16:54.750 -> BLE Write: READ
09:16:54.750 -> 
09:16:54.750 -> [215654][V][BLECharacteristic.cpp:353] setValue(): >> setValue: length=10, data=302c302c302c302c300a, characteristic UUID=6e400003-b5a3-f393-e0a9-e50e24dcca9e
09:16:54.750 -> [215655][V][FreeRTOS.cpp:179] take(): Semaphore taking: name: SetValue (0x40827d08), owner: <N/A> for <Unknown>
09:16:54.750 -> [215655][V][FreeRTOS.cpp:188] take(): Semaphore taken:  name: SetValue (0x40827d08), owner: <Unknown>
09:16:54.750 -> [215656][V][FreeRTOS.cpp:136] give(): Semaphore giving: name: SetValue (0x40827d08), owner: <Unknown>
09:16:54.750 -> [215656][V][BLECharacteristic.cpp:363] setValue(): << setValue
09:16:54.750 -> [215657][V][BLECharacteristic.cpp:1091] notify(): >> notify: length: 10
09:16:54.750 -> [215657][D][BLECharacteristic.cpp:468] onNotify(): >> onNotify: default
09:16:54.750 -> [215658][D][BLECharacteristic.cpp:469] onNotify(): << onNotify
09:16:54.750 -> [215658][V][GeneralUtils.cpp:304] hexDump():      00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
09:16:54.750 -> [215658][V][GeneralUtils.cpp:305] hexDump():      -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
09:16:54.750 -> [215659][V][GeneralUtils.cpp:331] hexDump(): 0000 30 2c 30 2c 30 2c 30 2c 30 0a                    0,0,0,0,0.
09:16:54.750 -> [215660][V][BLEServer.cpp:621] handleGATTServerEvent(): >> handleGAPEvent: BLE_GAP_EVENT_NOTIFY_TX
nRF Connect, 2025-10-28
ESP32_Skycommand_BLE (F0:F5:BD:02:A8:9A)
V	09:20:27.015	Connecting to F0:F5:BD:02:A8:9A...
D	09:20:27.015	gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D	09:20:27.127	[Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
D	09:20:27.134	[Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I	09:20:27.135	Connected to F0:F5:BD:02:A8:9A
V	09:20:27.136	Discovering services...
D	09:20:27.136	gatt.discoverServices()
I	09:20:27.304	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
I	09:20:27.851	Connection parameters updated (interval: 20.0ms, latency: 0, timeout: 5000ms)
D	09:20:28.174	[Callback] Services discovered with status: 0
I	09:20:28.174	Services discovered
V	09:20:28.179	Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
- Server Supported Features [R] (0x2B3A)
- Client Supported Features [R W] (0x2B29)
Nordic UART Service (6e400001-b5a3-f393-e0a9-e50e24dcca9e)
- TX Characteristic [N R] (6e400003-b5a3-f393-e0a9-e50e24dcca9e)
   Client Characteristic Configuration (0x2902)
- RX Characteristic [W WNR] (6e400002-b5a3-f393-e0a9-e50e24dcca9e)
D	09:20:28.179	gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D	09:20:28.183	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
I	09:20:28.382	Connection parameters updated (interval: 30.0ms, latency: 4, timeout: 5000ms)
V	09:20:30.685	Enabling notifications for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
D	09:20:30.685	gatt.setCharacteristicNotification(6e400003-b5a3-f393-e0a9-e50e24dcca9e, true)
D	09:20:30.687	gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I	09:20:30.810	Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A	09:20:30.810	"Notifications enabled" sent
V	09:20:30.813	Notifications enabled for 6e400003-b5a3-f393-e0a9-e50e24dcca9e
V	09:20:40.497	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:20:40.497	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	09:20:40.651	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	09:20:40.651	"CHAN;2100
" sent
I	09:20:40.680	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:20:40.680	"# Active channels se" received
V	09:21:07.857	Writing request to characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e
D	09:21:07.857	gatt.writeCharacteristic(6e400002-b5a3-f393-e0a9-e50e24dcca9e, value=0x4348414E3B323130300A)
I	09:21:07.921	Data written to 6e400002-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 43-48-41-4E-3B-32-31-30-30-0A
A	09:21:07.921	"CHAN;2100
" sent
I	09:21:07.951	Notification received from 6e400003-b5a3-f393-e0a9-e50e24dcca9e, value: (0x) 23-20-41-63-74-69-76-65-20-63-68-61-6E-6E-65-6C-73-20-73-65, "# Active channels se"
A	09:21:07.951	"# Active channels se" received