1+ /* *
2+ * @file RAK3112_BLE_UART.ino
3+ * @author Bernd Giesecke (bernd@giesecke.tk)
4+ * @brief BLE_UART example
5+ * Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
6+ * Ported to Arduino ESP32 by Evandro Copercini
7+ *
8+ * Create a BLE server that, once we receive a connection, will send periodic notifications.
9+ * The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
10+ * Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
11+ * Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
12+ *
13+ * The design of creating the BLE server is:
14+ * 1. Create a BLE Server
15+ * 2. Create a BLE Service
16+ * 3. Create a BLE Characteristic on the Service
17+ * 4. Create a BLE Descriptor on the characteristic
18+ * 5. Start the service.
19+ * 6. Start advertising.
20+ *
21+ * In this example rxValue is the data received (only accessible inside that function).
22+ * And txValue is the data to be sent, in this example whatever was received over the USB Serial.
23+ * @version 0.1
24+ * @date 2025-06-09
25+ *
26+ * @copyright Copyright (c) 2025
27+ *
28+ */
29+ #include < Arduino.h>
30+ #include < BLEDevice.h>
31+ #include < BLEServer.h>
32+ #include < BLEUtils.h>
33+ #include < BLE2902.h>
34+
35+ BLEServer *pServer = NULL ;
36+ BLECharacteristic *pTxCharacteristic;
37+ bool deviceConnected = false ;
38+ bool oldDeviceConnected = false ;
39+ uint8_t txValue = 0x30 ;
40+
41+ // See the following for generating UUIDs:
42+ // https://www.uuidgenerator.net/
43+
44+ #define SERVICE_UUID " 6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
45+ #define CHARACTERISTIC_UUID_RX " 6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // UART RX characteristic UUID
46+ #define CHARACTERISTIC_UUID_TX " 6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // UART TX characteristic UUID
47+
48+ /* *
49+ * @brief BLE connection/disconnection callback
50+ *
51+ */
52+ class MyServerCallbacks : public BLEServerCallbacks
53+ {
54+ void onConnect (BLEServer *pServer)
55+ {
56+ deviceConnected = true ;
57+ };
58+
59+ void onDisconnect (BLEServer *pServer)
60+ {
61+ deviceConnected = false ;
62+ }
63+ };
64+
65+ /* *
66+ * @brief BLE UART write callback (data received)
67+ *
68+ */
69+ class MyCallbacks : public BLECharacteristicCallbacks
70+ {
71+ void onWrite (BLECharacteristic *pCharacteristic)
72+ {
73+ String rxValue = pCharacteristic->getValue ();
74+
75+ if (rxValue.length () > 0 )
76+ {
77+ Serial.println (" *********" );
78+ Serial.print (" Received Value: " );
79+ for (int i = 0 ; i < rxValue.length (); i++)
80+ {
81+ Serial.print (rxValue[i]);
82+ }
83+
84+ Serial.println ();
85+ Serial.println (" *********" );
86+ }
87+ }
88+ };
89+
90+ /* *
91+ * @brief Arduino setup function, called once
92+ *
93+ */
94+ void setup (void )
95+ {
96+ // Prepare LED's BLUE ==> TX, GREEN ==> Received a packet
97+ pinMode (LED_GREEN, OUTPUT);
98+ pinMode (LED_BLUE, OUTPUT);
99+ digitalWrite (LED_GREEN, LOW);
100+ digitalWrite (LED_BLUE, LOW);
101+
102+ // Initialize Serial for debug output
103+ Serial.begin (115200 );
104+ time_t serial_timeout = millis ();
105+ // On nRF52840 the USB serial is not available immediately
106+ while (!Serial)
107+ {
108+ if ((millis () - serial_timeout) < 5000 )
109+ {
110+ delay (100 );
111+ digitalWrite (LED_GREEN, !digitalRead (LED_GREEN));
112+ }
113+ else
114+ {
115+ break ;
116+ }
117+ }
118+ digitalWrite (LED_GREEN, LOW);
119+
120+ // Create the BLE Device
121+ BLEDevice::init (" UART Service" );
122+
123+ // Create the BLE Server
124+ pServer = BLEDevice::createServer ();
125+ pServer->setCallbacks (new MyServerCallbacks ());
126+
127+ // Create the BLE Service
128+ BLEService *pService = pServer->createService (SERVICE_UUID);
129+
130+ // Create a BLE Characteristic
131+ pTxCharacteristic = pService->createCharacteristic (CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
132+
133+ pTxCharacteristic->addDescriptor (new BLE2902 ());
134+
135+ BLECharacteristic *pRxCharacteristic = pService->createCharacteristic (CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
136+
137+ pRxCharacteristic->setCallbacks (new MyCallbacks ());
138+
139+ // Start the service
140+ pService->start ();
141+
142+ // Start advertising
143+ pServer->getAdvertising ()->start ();
144+ Serial.println (" Waiting a client connection to notify..." );
145+ }
146+
147+ /* *
148+ * @brief Arduino loop, runs forever
149+ *
150+ */
151+ void loop (void )
152+ {
153+ if (deviceConnected)
154+ {
155+ if (Serial.available ())
156+ {
157+ while (Serial.available ())
158+ {
159+ txValue = Serial.read ();
160+ pTxCharacteristic->setValue (&txValue, 1 );
161+ pTxCharacteristic->notify ();
162+ delay (10 ); // bluetooth stack will go into congestion, if too many packets are sent
163+ }
164+ }
165+ }
166+
167+ // disconnecting
168+ if (!deviceConnected && oldDeviceConnected)
169+ {
170+ delay (500 ); // give the bluetooth stack the chance to get things ready
171+ pServer->startAdvertising (); // restart advertising
172+ Serial.println (" start advertising" );
173+ oldDeviceConnected = deviceConnected;
174+ }
175+ // connecting
176+ if (deviceConnected && !oldDeviceConnected)
177+ {
178+ // do stuff here on connecting
179+ oldDeviceConnected = deviceConnected;
180+ }
181+ }
0 commit comments