Skip to content

Commit fecc914

Browse files
Copiloth2zero
andcommitted
Fix NimBLE_Stream_Server NUS compatibility: add two-characteristic support
Agent-Logs-Url: https://github.com/h2zero/NimBLE-Arduino/sessions/07db667d-a538-4e10-93a5-e30616f1f6a9 Co-authored-by: h2zero <32826625+h2zero@users.noreply.github.com>
1 parent 471bf1c commit fecc914

6 files changed

Lines changed: 347 additions & 52 deletions

File tree

examples/NimBLE_Stream_Client/NimBLE_Stream_Client.ino

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* This allows you to use familiar methods like print(), println(),
88
* read(), and available() over BLE, similar to how you would use Serial.
99
*
10-
* This example connects to the NimBLE_Stream_Server example.
10+
* This example connects to the NimBLE_Stream_Server example using the Nordic UART
11+
* Service (NUS) with separate TX and RX characteristics.
1112
*
1213
* Created: November 2025
1314
* Author: NimBLE-Arduino Contributors
@@ -16,9 +17,10 @@
1617
#include <Arduino.h>
1718
#include <NimBLEDevice.h>
1819

19-
// Service and Characteristic UUIDs (must match the server)
20-
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
21-
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
20+
// Nordic UART Service (NUS) UUIDs (must match the server)
21+
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
22+
#define TX_CHAR_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // Server TX: client subscribes here
23+
#define RX_CHAR_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // Server RX: client writes here
2224

2325
// Create the stream client instance
2426
NimBLEStreamClient bleStream;
@@ -116,7 +118,7 @@ bool connectToServer() {
116118

117119
Serial.println("Connected! Discovering services...");
118120

119-
// Get the service and characteristic
121+
// Get the service
120122
NimBLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
121123
if (!pRemoteService) {
122124
Serial.println("Failed to find our service UUID");
@@ -125,19 +127,30 @@ bool connectToServer() {
125127
}
126128
Serial.println("Found the stream service");
127129

128-
NimBLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
129-
if (!pRemoteCharacteristic) {
130-
Serial.println("Failed to find our characteristic UUID");
130+
// Get the TX characteristic (server sends notifications here; client subscribes for RX)
131+
NimBLERemoteCharacteristic* pTxChar = pRemoteService->getCharacteristic(TX_CHAR_UUID);
132+
if (!pTxChar) {
133+
Serial.println("Failed to find TX characteristic");
131134
pClient->disconnect();
132135
return false;
133136
}
134-
Serial.println("Found the stream characteristic");
137+
Serial.println("Found the TX characteristic");
138+
139+
// Get the RX characteristic (server receives writes here; client writes for TX)
140+
NimBLERemoteCharacteristic* pRxChar = pRemoteService->getCharacteristic(RX_CHAR_UUID);
141+
if (!pRxChar) {
142+
Serial.println("Failed to find RX characteristic");
143+
pClient->disconnect();
144+
return false;
145+
}
146+
Serial.println("Found the RX characteristic");
135147

136148
/**
137-
* Initialize the stream client with the remote characteristic
138-
* subscribeNotify=true means we'll receive notifications in the RX buffer
149+
* Initialize the stream client with separate TX and RX characteristics:
150+
* - pRxChar: the characteristic we write to (our TX = server's RX, UUID 6E400002)
151+
* - pTxChar: the characteristic we subscribe to (our RX = server's TX, UUID 6E400003)
139152
*/
140-
if (!bleStream.begin(pRemoteCharacteristic, true)) {
153+
if (!bleStream.begin(pRxChar, pTxChar)) {
141154
Serial.println("Failed to initialize BLE stream!");
142155
pClient->disconnect();
143156
return false;

examples/NimBLE_Stream_Client/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ This example demonstrates how to use the `NimBLEStreamClient` class to connect t
66

77
- Uses Arduino Stream interface (print, println, read, available, etc.)
88
- Automatic server discovery and connection
9-
- Bidirectional communication
9+
- Bidirectional communication using the Nordic UART Service (NUS)
1010
- Buffered TX/RX using ring buffers
1111
- Automatic reconnection on disconnect
12+
- Compatible with NUS terminal apps and the NimBLE_Stream_Server example
1213
- Similar usage to Serial communication
1314

1415
## How it Works
1516

16-
1. Scans for BLE devices advertising the target service UUID
17-
2. Connects to the server and discovers the stream characteristic
18-
3. Initializes `NimBLEStreamClient` with the remote characteristic
19-
4. Subscribes to notifications to receive data in the RX buffer
17+
1. Scans for BLE devices advertising the NUS service UUID
18+
2. Connects to the server and discovers the TX and RX characteristics
19+
3. Initializes `NimBLEStreamClient` with separate TX (write) and RX (subscribe) characteristics
20+
4. Subscribes to the TX characteristic to receive data in the RX buffer
2021
5. Uses familiar Stream methods like `print()`, `println()`, `read()`, and `available()`
2122

2223
## Usage
@@ -30,11 +31,12 @@ This example demonstrates how to use the `NimBLEStreamClient` class to connect t
3031
- Begin bidirectional communication
3132
4. You can also type in the Serial monitor to send data to the server
3233

33-
## Service UUIDs
34+
## Service UUIDs (Nordic UART Service)
3435

3536
Must match the server:
3637
- Service: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
37-
- Characteristic: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
38+
- TX Characteristic (server → client, client subscribes): `6E400003-B5A3-F393-E0A9-E50E24DCCA9E`
39+
- RX Characteristic (client → server, client writes): `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
3840

3941
## Serial Monitor Output
4042

examples/NimBLE_Stream_Server/NimBLE_Stream_Server.ino

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* This allows you to use familiar methods like print(), println(),
88
* read(), and available() over BLE, similar to how you would use Serial.
99
*
10+
* Uses the Nordic UART Service (NUS) UUIDs with separate TX and RX characteristics
11+
* for compatibility with NUS terminal apps (e.g. nRF UART, Serial Bluetooth Terminal).
12+
*
1013
* Created: November 2025
1114
* Author: NimBLE-Arduino Contributors
1215
*/
@@ -36,10 +39,11 @@ NimBLEStream::RxOverflowAction onRxOverflow(const uint8_t* data, size_t len, voi
3639
return NimBLEStream::DROP_OLDER_DATA;
3740
}
3841

39-
// Service and Characteristic UUIDs for the stream
40-
// Using custom UUIDs - you can change these as needed
41-
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
42-
#define CHARACTERISTIC_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
42+
// Nordic UART Service (NUS) UUIDs
43+
// Using separate TX and RX characteristics for compatibility with NUS terminal apps.
44+
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
45+
#define TX_CHAR_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // Server TX: notify (server → client)
46+
#define RX_CHAR_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // Server RX: write (client → server)
4347

4448
/** Server callbacks to handle connection/disconnection events */
4549
class ServerCallbacks : public NimBLEServerCallbacks {
@@ -68,21 +72,23 @@ void setup() {
6872

6973
/**
7074
* Create the BLE server and set callbacks
71-
* Note: The stream will create its own service and characteristic
75+
* Note: The stream will create its own service and characteristics
7276
*/
7377
NimBLEServer* pServer = NimBLEDevice::createServer();
7478
pServer->setCallbacks(&serverCallbacks);
7579

7680
/**
77-
* Initialize the stream server with:
81+
* Initialize the stream server with NUS UUIDs using separate TX and RX characteristics:
7882
* - Service UUID
79-
* - Characteristic UUID
83+
* - TX Characteristic UUID: server sends notifications here (client subscribes)
84+
* - RX Characteristic UUID: client writes here (server receives)
8085
* - txBufSize: 1024 bytes for outgoing data (notifications)
8186
* - rxBufSize: 1024 bytes for incoming data (writes)
8287
* - secure: false (no encryption required - set to true for secure connections)
8388
*/
8489
if (!bleStream.begin(NimBLEUUID(SERVICE_UUID),
85-
NimBLEUUID(CHARACTERISTIC_UUID),
90+
NimBLEUUID(TX_CHAR_UUID),
91+
NimBLEUUID(RX_CHAR_UUID),
8692
1024, // txBufSize
8793
1024, // rxBufSize
8894
false)) // secure

examples/NimBLE_Stream_Server/README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,38 @@ This example demonstrates how to use the `NimBLEStreamServer` class to create a
66

77
- Uses Arduino Stream interface (print, println, read, available, etc.)
88
- Automatic connection management
9-
- Bidirectional communication
9+
- Bidirectional communication using the Nordic UART Service (NUS)
1010
- Buffered TX/RX using ring buffers
11+
- Compatible with NUS terminal apps (nRF UART, Serial Bluetooth Terminal, etc.)
1112
- Similar usage to Serial communication
1213

1314
## How it Works
1415

15-
1. Creates a BLE GATT server with a custom service and characteristic
16-
2. Initializes `NimBLEStreamServer` with the characteristic configured for notifications and writes
16+
1. Creates a BLE GATT server with the NUS service and two separate characteristics (TX and RX)
17+
2. Initializes `NimBLEStreamServer` with separate TX (notify) and RX (write) characteristics
1718
3. Uses familiar Stream methods like `print()`, `println()`, `read()`, and `available()`
1819
4. Automatically handles connection state and MTU negotiation
1920

2021
## Usage
2122

2223
1. Upload this sketch to your ESP32
2324
2. The device will advertise as "NimBLE-Stream"
24-
3. Connect with a BLE client (such as the NimBLE_Stream_Client example or a mobile app)
25+
3. Connect with a BLE client (such as the NimBLE_Stream_Client example or a NUS terminal app)
2526
4. Once connected, the server will:
2627
- Send periodic messages to the client
2728
- Echo back any data received from the client
2829
- Display all communication on the Serial monitor
2930

30-
## Service UUIDs
31+
## Service UUIDs (Nordic UART Service)
3132

3233
- Service: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
33-
- Characteristic: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
34-
35-
These are based on the Nordic UART Service (NUS) UUIDs for compatibility with many BLE terminal apps.
34+
- TX Characteristic (server → client, notify): `6E400003-B5A3-F393-E0A9-E50E24DCCA9E`
35+
- RX Characteristic (client → server, write): `6E400002-B5A3-F393-E0A9-E50E24DCCA9E`
3636

3737
## Compatible With
3838

3939
- NimBLE_Stream_Client example
4040
- nRF Connect mobile app
41-
- Serial Bluetooth Terminal apps
42-
- Any BLE client that supports characteristic notifications and writes
41+
- nRF UART app
42+
- Serial Bluetooth Terminal app
43+
- Any BLE client that supports the Nordic UART Service (NUS)

0 commit comments

Comments
 (0)