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,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)
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:
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+ ***************************************************************************/
65171static 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
98287static 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
127407void 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