Skip to content

Commit ad18f5f

Browse files
authored
Merge pull request espressif#11813 from lucasssvaz/feat/simpleBLE_nimble
feat(simpleBLE): Add support for NimBLE
2 parents 2f64f03 + f4bb3ae commit ad18f5f

File tree

4 files changed

+294
-16
lines changed

4 files changed

+294
-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: 282 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,87 @@ 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: log_d("BLE_GAP_EVENT_ADV_COMPLETE"); break;
152+
default: break;
153+
}
154+
return 0;
155+
}
156+
#endif
64157

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

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

107378
/*
@@ -121,11 +392,18 @@ bool SimpleBLE::begin(String localName) {
121392
if (localName.length()) {
122393
local_name = localName;
123394
}
395+
396+
// If already initialized, just update advertising data
397+
if (_ble_initialized) {
398+
return _update_advertising(local_name.c_str());
399+
}
400+
124401
return _init_gap(local_name.c_str());
125402
}
126403

127404
void SimpleBLE::end() {
128405
_stop_gap();
129406
}
130407

131-
#endif
408+
#endif // CONFIG_BLUEDROID_ENABLED || CONFIG_NIMBLE_ENABLED
409+
#endif // SOC_BLE_SUPPORTED || CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE

0 commit comments

Comments
 (0)