Skip to content

Commit 68d39df

Browse files
committed
feat(simpleBLE): Add support for NimBLE
1 parent a39d1bd commit 68d39df

File tree

4 files changed

+297
-16
lines changed

4 files changed

+297
-16
lines changed

libraries/BluetoothSerial/src/BluetoothSerial.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ typedef std::function<void()> KeyRequestCb;
3535
typedef std::function<void(boolean success)> AuthCompleteCb;
3636
typedef std::function<void(BTAdvertisedDevice *pAdvertisedDevice)> BTAdvertisedDeviceCb;
3737

38-
class BluetoothSerial : public Stream {
38+
class [[deprecated("BluetoothSerial won't be supported in version 4.0.0 by default")]] BluetoothSerial : public Stream {
3939
public:
4040
BluetoothSerial(void);
4141
~BluetoothSerial(void);

libraries/SimpleBLE/examples/SimpleBleDevice/SimpleBleDevice.ino

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818

1919
#include "SimpleBLE.h"
2020

21-
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
22-
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
23-
#endif
24-
2521
SimpleBLE ble;
2622

2723
void onButton() {
@@ -34,7 +30,7 @@ void onButton() {
3430
void setup() {
3531
Serial.begin(115200);
3632
Serial.setDebugOutput(true);
37-
pinMode(0, INPUT_PULLUP);
33+
pinMode(BOOT_PIN, INPUT_PULLUP);
3834
Serial.print("ESP32 SDK: ");
3935
Serial.println(ESP.getSdkVersion());
4036
ble.begin("ESP32 SimpleBLE");
@@ -43,7 +39,7 @@ void setup() {
4339

4440
void loop() {
4541
static uint8_t lastPinState = 1;
46-
uint8_t pinState = digitalRead(0);
42+
uint8_t pinState = digitalRead(BOOT_PIN);
4743
if (!pinState && lastPinState) {
4844
onButton();
4945
}

libraries/SimpleBLE/src/SimpleBLE.cpp

Lines changed: 285 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,56 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#include "sdkconfig.h"
1615
#include "soc/soc_caps.h"
17-
18-
#if SOC_BT_SUPPORTED && defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED)
16+
#include "sdkconfig.h"
17+
#if defined(SOC_BLE_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)
18+
#if defined(CONFIG_BLUEDROID_ENABLED) || defined(CONFIG_NIMBLE_ENABLED)
1919

2020
#include "SimpleBLE.h"
2121
#include "esp32-hal-log.h"
2222

23+
#if defined(SOC_BLE_SUPPORTED)
2324
#include "esp_bt.h"
25+
#endif
26+
27+
/***************************************************************************
28+
* Bluedroid includes *
29+
***************************************************************************/
30+
#if defined(CONFIG_BLUEDROID_ENABLED)
2431
#include "esp_gap_ble_api.h"
2532
#include "esp_gatts_api.h"
2633
#include "esp_bt_defs.h"
2734
#include "esp_bt_main.h"
35+
#endif
36+
37+
/***************************************************************************
38+
* NimBLE includes *
39+
***************************************************************************/
40+
#if defined(CONFIG_NIMBLE_ENABLED)
41+
#include <host/ble_gap.h>
42+
#include <host/ble_hs.h>
43+
#include <host/ble_store.h>
44+
#include <store/config/ble_store_config.h>
45+
#include <services/gap/ble_svc_gap.h>
46+
#include <nimble/nimble_port.h>
47+
#include <nimble/nimble_port_freertos.h>
48+
49+
#ifdef CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE
50+
#include <esp_nimble_hci.h>
51+
#endif
52+
53+
// Forward declaration
54+
extern "C" void ble_store_config_init(void);
55+
#endif
56+
57+
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)
58+
#include "esp32-hal-hosted.h"
59+
#endif
2860

61+
/***************************************************************************
62+
* Bluedroid data structures *
63+
***************************************************************************/
64+
#if defined(CONFIG_BLUEDROID_ENABLED)
2965
static esp_ble_adv_data_t _adv_config = {
3066
.set_scan_rsp = false,
3167
.include_name = true,
@@ -55,14 +91,90 @@ static esp_ble_adv_params_t _adv_params = {
5591
.channel_map = ADV_CHNL_ALL,
5692
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
5793
};
94+
#endif
95+
96+
/***************************************************************************
97+
* NimBLE data structures *
98+
***************************************************************************/
99+
#if defined(CONFIG_NIMBLE_ENABLED)
100+
static struct ble_hs_adv_fields _nimble_adv_fields;
101+
static struct ble_gap_adv_params _nimble_adv_params = {
102+
.conn_mode = BLE_GAP_CONN_MODE_NON,
103+
.disc_mode = BLE_GAP_DISC_MODE_GEN,
104+
.itvl_min = 512,
105+
.itvl_max = 1024,
106+
.channel_map = 0,
107+
.filter_policy = 0,
108+
.high_duty_cycle = 0,
109+
};
58110

111+
// Global variables for NimBLE synchronization
112+
static bool _nimble_synced = false;
113+
#endif
114+
115+
// Global state tracking
116+
static bool _ble_initialized = false;
117+
118+
/***************************************************************************
119+
* Bluedroid callbacks *
120+
***************************************************************************/
121+
#if defined(CONFIG_BLUEDROID_ENABLED)
59122
static void _on_gap(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
60123
if (event == ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT) {
61124
esp_ble_gap_start_advertising(&_adv_params);
62125
}
63126
}
127+
#endif
128+
129+
/***************************************************************************
130+
* NimBLE callbacks *
131+
***************************************************************************/
132+
#if defined(CONFIG_NIMBLE_ENABLED)
133+
static void _nimble_host_task(void *param) {
134+
// This function will be called to run the BLE host
135+
nimble_port_run();
136+
// Should never reach here unless nimble_port_stop() is called
137+
nimble_port_freertos_deinit();
138+
}
139+
140+
static void _nimble_on_reset(int reason) {
141+
log_i("NimBLE reset; reason=%d", reason);
142+
}
143+
144+
static void _nimble_on_sync(void) {
145+
log_i("NimBLE sync complete");
146+
_nimble_synced = true;
147+
}
148+
149+
static int _nimble_gap_event(struct ble_gap_event *event, void *arg) {
150+
switch (event->type) {
151+
case BLE_GAP_EVENT_ADV_COMPLETE:
152+
log_d("BLE_GAP_EVENT_ADV_COMPLETE");
153+
break;
154+
default:
155+
break;
156+
}
157+
return 0;
158+
}
159+
#endif
64160

161+
/***************************************************************************
162+
* Forward declarations *
163+
***************************************************************************/
164+
static bool _init_gap(const char *name);
165+
static bool _stop_gap();
166+
static bool _update_advertising(const char *name);
167+
168+
/***************************************************************************
169+
* Initialization functions *
170+
***************************************************************************/
65171
static bool _init_gap(const char *name) {
172+
if (_ble_initialized) {
173+
log_d("BLE already initialized, skipping");
174+
return true;
175+
}
176+
177+
#if defined(CONFIG_BLUEDROID_ENABLED)
66178
if (!btStarted() && !btStart()) {
67179
log_e("btStart failed");
68180
return false;
@@ -92,16 +204,178 @@ static bool _init_gap(const char *name) {
92204
log_e("gap_register_callback failed");
93205
return false;
94206
}
207+
_ble_initialized = true;
95208
return true;
209+
#elif defined(CONFIG_NIMBLE_ENABLED)
210+
#if defined(CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE)
211+
// Initialize esp-hosted transport for BLE HCI when explicitly enabled
212+
if (!hostedInitBLE()) {
213+
log_e("Failed to initialize ESP-Hosted for BLE");
214+
return false;
215+
}
216+
#endif
217+
218+
esp_err_t errRc = nimble_port_init();
219+
if (errRc != ESP_OK) {
220+
log_e("nimble_port_init: rc=%d", errRc);
221+
return false;
222+
}
223+
224+
// Configure NimBLE host
225+
ble_hs_cfg.reset_cb = _nimble_on_reset;
226+
ble_hs_cfg.sync_cb = _nimble_on_sync;
227+
ble_hs_cfg.sm_io_cap = BLE_HS_IO_NO_INPUT_OUTPUT;
228+
ble_hs_cfg.sm_bonding = 0;
229+
ble_hs_cfg.sm_mitm = 0;
230+
ble_hs_cfg.sm_sc = 1;
231+
232+
// Set device name
233+
errRc = ble_svc_gap_device_name_set(name);
234+
if (errRc != ESP_OK) {
235+
log_e("ble_svc_gap_device_name_set: rc=%d", errRc);
236+
return false;
237+
}
238+
239+
// Configure advertising data
240+
memset(&_nimble_adv_fields, 0, sizeof(_nimble_adv_fields));
241+
_nimble_adv_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
242+
_nimble_adv_fields.name = (uint8_t *)name;
243+
_nimble_adv_fields.name_len = strlen(name);
244+
_nimble_adv_fields.name_is_complete = 1;
245+
_nimble_adv_fields.tx_pwr_lvl_is_present = 1;
246+
247+
// Initialize store configuration
248+
ble_store_config_init();
249+
250+
// Start the host task
251+
nimble_port_freertos_init(_nimble_host_task);
252+
253+
// Wait for sync
254+
int sync_timeout = 1000; // 10 seconds timeout
255+
while (!_nimble_synced && sync_timeout > 0) {
256+
vTaskDelay(pdMS_TO_TICKS(10));
257+
sync_timeout--;
258+
}
259+
260+
if (!_nimble_synced) {
261+
log_e("NimBLE sync timeout");
262+
return false;
263+
}
264+
265+
// Set advertising data
266+
errRc = ble_gap_adv_set_fields(&_nimble_adv_fields);
267+
if (errRc != ESP_OK) {
268+
log_e("ble_gap_adv_set_fields: rc=%d", errRc);
269+
return false;
270+
}
271+
272+
// Start advertising
273+
errRc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &_nimble_adv_params, _nimble_gap_event, NULL);
274+
if (errRc != ESP_OK) {
275+
log_e("ble_gap_adv_start: rc=%d", errRc);
276+
return false;
277+
}
278+
279+
_ble_initialized = true;
280+
return true;
281+
#else
282+
log_e("No BLE stack enabled");
283+
return false;
284+
#endif
96285
}
97286

98287
static bool _stop_gap() {
288+
if (!_ble_initialized) {
289+
log_d("BLE not initialized, nothing to stop");
290+
return true;
291+
}
292+
293+
#if defined(CONFIG_BLUEDROID_ENABLED)
99294
if (btStarted()) {
100295
esp_bluedroid_disable();
101296
esp_bluedroid_deinit();
102297
btStop();
103298
}
299+
_ble_initialized = false;
300+
return true;
301+
#elif defined(CONFIG_NIMBLE_ENABLED)
302+
// Stop advertising
303+
ble_gap_adv_stop();
304+
305+
// Stop NimBLE
306+
int rc = nimble_port_stop();
307+
if (rc != ESP_OK) {
308+
log_e("nimble_port_stop: rc=%d", rc);
309+
}
310+
311+
nimble_port_deinit();
312+
_nimble_synced = false;
313+
_ble_initialized = false;
314+
104315
return true;
316+
#else
317+
return true;
318+
#endif
319+
}
320+
321+
static bool _update_advertising(const char *name) {
322+
if (!_ble_initialized) {
323+
log_e("BLE not initialized");
324+
return false;
325+
}
326+
327+
#if defined(CONFIG_BLUEDROID_ENABLED)
328+
// Stop current advertising
329+
esp_ble_gap_stop_advertising();
330+
331+
// Set new device name
332+
if (esp_ble_gap_set_device_name(name)) {
333+
log_e("gap_set_device_name failed");
334+
return false;
335+
}
336+
337+
// Restart advertising with new name
338+
if (esp_ble_gap_config_adv_data(&_adv_config)) {
339+
log_e("gap_config_adv_data failed");
340+
return false;
341+
}
342+
343+
return true;
344+
#elif defined(CONFIG_NIMBLE_ENABLED)
345+
// Stop current advertising
346+
ble_gap_adv_stop();
347+
348+
// Set new device name
349+
int errRc = ble_svc_gap_device_name_set(name);
350+
if (errRc != ESP_OK) {
351+
log_e("ble_svc_gap_device_name_set: rc=%d", errRc);
352+
return false;
353+
}
354+
355+
// Update advertising fields with new name
356+
_nimble_adv_fields.name = (uint8_t *)name;
357+
_nimble_adv_fields.name_len = strlen(name);
358+
_nimble_adv_fields.name_is_complete = 1;
359+
360+
// Set new advertising data
361+
errRc = ble_gap_adv_set_fields(&_nimble_adv_fields);
362+
if (errRc != ESP_OK) {
363+
log_e("ble_gap_adv_set_fields: rc=%d", errRc);
364+
return false;
365+
}
366+
367+
// Restart advertising
368+
errRc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &_nimble_adv_params, _nimble_gap_event, NULL);
369+
if (errRc != ESP_OK) {
370+
log_e("ble_gap_adv_start: rc=%d", errRc);
371+
return false;
372+
}
373+
374+
return true;
375+
#else
376+
log_e("No BLE stack enabled");
377+
return false;
378+
#endif
105379
}
106380

107381
/*
@@ -121,11 +395,18 @@ bool SimpleBLE::begin(String localName) {
121395
if (localName.length()) {
122396
local_name = localName;
123397
}
398+
399+
// If already initialized, just update advertising data
400+
if (_ble_initialized) {
401+
return _update_advertising(local_name.c_str());
402+
}
403+
124404
return _init_gap(local_name.c_str());
125405
}
126406

127407
void SimpleBLE::end() {
128408
_stop_gap();
129409
}
130410

131-
#endif
411+
#endif // CONFIG_BLUEDROID_ENABLED || CONFIG_NIMBLE_ENABLED
412+
#endif // SOC_BLE_SUPPORTED || CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE

0 commit comments

Comments
 (0)