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)
2965static 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)
59122static 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+ ***************************************************************************/
65168static 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
98284static 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
127404void 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