espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.91k stars 7.33k forks source link

NimBLE Gatt Server & ESP-BLE-MESH provisioner coexistence (IDFGH-13522) #14413

Open buganini opened 3 months ago

buganini commented 3 months ago

Answers checklist.

General issue report

ESP-IDF: v5.3

sdkconfig includes:

CONFIG_BLE_MESH_SUPPORT_BLE_ADV=y
CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT=2

I used to have Bluedroid Gatt Server + ESP-BLE-MESH coexistence by using esp_ble_mesh_start_ble_advertising, it will send both advertisements and both gatts_profile_event_handler/esp_ble_mesh_prov_callback are invoked to handle BLE pairing/bonding and BLE-MESH provisioning.

But due to the following issue I have to move to NimBLE https://github.com/meshtastic/firmware/issues/266

NimBLE GATT Server works and ESP-IDF-MESH works, but when both are enabled, only one of them functions correctly.

With NimBLE I have to call ble_gap_adv_start to register GAP event handler for pairing/bonding, I have tried different combinations and orders of esp_ble_mesh_start_ble_advertising, ble_gap_adv_start, esp_ble_mesh_init/esp_ble_mesh_provisioner_prov_enable , but I just cannot get both handlers to work simultaneously. It seems that ESP-BLE-MESH is not integrated with NimBLE. Can someone confirm this?

Laosepy commented 2 months ago

HI,must use nimble-mesh,This comes from the accompanying code for nimble,But the examples provided in the idf seem to have bugs,first running ,I found that it wouldn't broadcast, and there was a stack error after I corrected the sample code as explained in the comments

buganini commented 1 month ago

I am using this patch to have my NimBLE GATT Services + ESP-BLE-MESH working together

Changes

Patches

diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
index 1cb239a3ca..2a0b1a8077 100644
--- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
+++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
@@ -20,6 +20,8 @@
 extern "C" {
 #endif

+#define BLE_MESH_EXT_ADV_IDX 0
+
 /* BLE Mesh Max Connection Count */
 #ifdef CONFIG_BT_BLUEDROID_ENABLED
 #define BLE_MESH_MAX_CONN   CONFIG_BT_ACL_CONNECTIONS
@@ -513,7 +515,7 @@ struct bt_mesh_conn_cb {
      *  @param conn New connection object.
      *  @param err HCI error. Zero for success, non-zero otherwise.
      */
-    void (*connected)(struct bt_mesh_conn *conn, uint8_t err);
+    void (*connected)(struct bt_mesh_conn *conn, uint8_t status);

     /** @brief A connection has been disconnected.
      *
@@ -718,6 +720,8 @@ int bt_le_update_white_list(struct bt_mesh_white_list *wl);

 void bt_mesh_gatts_conn_cb_register(struct bt_mesh_conn_cb *cb);
 void bt_mesh_gatts_conn_cb_deregister(void);
+struct bt_mesh_conn_cb * bt_mesh_gatts_conn_cb_current();
+int (*bt_mesh_gap_event_cb(void))(struct ble_gap_event *event, void *arg);

 int bt_mesh_gatts_disconnect(struct bt_mesh_conn *conn, uint8_t reason);

@@ -799,6 +803,8 @@ int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16],
 int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16],
                        uint8_t enc_data[16]);

+void esp_ble_mesh_init_gatts(void);
+
 enum {
     BLE_MESH_EXCEP_LIST_SUB_CODE_ADD = 0,
     BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE,
diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
index 0418b76c54..9d0e9e40cb 100644
--- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
+++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
@@ -17,6 +17,7 @@
 #include "host/ble_hs.h"
 #include "host/ble_uuid.h"
 #include "host/ble_att.h"
+#include "host/ble_gap.h"
 #include "host/ble_gatt.h"
 #include "services/gap/ble_svc_gap.h"
 #include "services/gatt/ble_svc_gatt.h"
@@ -652,7 +653,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg)
             uint8_t index = BLE_MESH_GATT_GET_CONN_ID(event->connect.conn_handle);
             if (index < BLE_MESH_MAX_CONN) {
                 bt_mesh_gatts_conn[index].handle = BLE_MESH_GATT_GET_CONN_ID(event->connect.conn_handle);
-                (bt_mesh_gatts_conn_cb->connected)(&bt_mesh_gatts_conn[index], 0);
+                (bt_mesh_gatts_conn_cb->connected)(&bt_mesh_gatts_conn[index], event->connect.status);
             }
             memcpy(bt_mesh_gatts_addr, desc.peer_id_addr.val, BLE_MESH_ADDR_LEN);
             /* This is for EspBleMesh Android app. When it tries to connect with the
@@ -777,6 +778,21 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg)
 }
 #endif /* CONFIG_BLE_MESH_NODE */

+#if MYNEWT_VAL(BLE_EXT_ADV)
+struct ble_gap_ext_adv_params params = {
+    .connectable = 1,
+    .scannable = 1,
+    .directed = 0,
+    .own_addr_type = BLE_OWN_ADDR_PUBLIC,
+    .primary_phy = BLE_HCI_LE_PHY_1M,
+    .secondary_phy = BLE_HCI_LE_PHY_2M,
+    .sid = BLE_MESH_EXT_ADV_IDX,
+    .itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .legacy_pdu = 1,
+};
+#endif
+
 /* APIs functions */
 int bt_le_adv_start(const struct bt_mesh_adv_param *param,
                     const struct bt_mesh_adv_data *ad, size_t ad_len,
@@ -800,6 +816,71 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param,
         return err;
     }

+#if MYNEWT_VAL(BLE_EXT_ADV)
+    if (ble_gap_ext_adv_active(BLE_MESH_EXT_ADV_IDX))
+    {
+        ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+    }
+
+    err = ble_gap_ext_adv_configure(BLE_MESH_EXT_ADV_IDX, &params, NULL,
+                                   gap_event_cb, NULL);
+    if (err != 0) {
+        BT_ERR("Extended Advertising configure failed: err %d", err);
+        return err;
+    }
+
+    struct os_mbuf *data = os_msys_get_pkthdr(buf_len, 0);
+    if (data == NULL) {
+        BT_ERR("Extended Advertising configure failed: os_msys_get_pkthdr");
+        return -1;
+    }
+
+    err = os_mbuf_append(data, buf, buf_len);
+    if (err != 0) {
+        BT_ERR("Extended Advertising os_mbuf_append failed: err %d", err);
+        return err;
+    }
+
+    err = ble_gap_ext_adv_set_data(BLE_MESH_EXT_ADV_IDX, data);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_set_data failed: err %d", err);
+        return err;
+    }
+
+    if (sd && (param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) {
+        buf_len = 0;
+
+        err = set_ad(sd, sd_len, buf, &buf_len);
+        if (err) {
+            BT_ERR("set_ad failed: err %d", err);
+            return err;
+        }
+
+        struct os_mbuf *rsp_data = os_msys_get_pkthdr(buf_len, 0);
+        if (rsp_data == NULL) {
+            BT_ERR("Extended Advertising configure rsp failed: os_msys_get_pkthdr");
+            return -1;
+        }
+
+        err = os_mbuf_append(rsp_data, buf, buf_len);
+        if (err != 0) {
+            BT_ERR("Extended Advertising rsp os_mbuf_append failed: err %d", err);
+            return err;
+        }
+
+        err = ble_gap_ext_adv_rsp_set_data(BLE_MESH_EXT_ADV_IDX, rsp_data);
+        if (err != 0) {
+            BT_ERR("Extended Advertising ble_gap_ext_adv_rsp_set_data failed: err %d", err);
+            return err;
+        }
+    }
+
+    err = ble_gap_ext_adv_start(BLE_MESH_EXT_ADV_IDX, 0, 0);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_start failed: err %d", err);
+        return err;
+    }
+#else
     err = ble_gap_adv_set_data(buf, buf_len);
     if (err != 0) {
         BT_ERR("Advertising set failed: err %d", err);
@@ -866,6 +947,7 @@ again:
         BT_ERR("Advertising start failed: err %d", err);
         return err;
     }
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -959,7 +1041,12 @@ int bt_le_adv_stop(void)
         return 0;
     }
 #endif
+
+#if MYNEWT_VAL(BLE_EXT_ADV)
+    ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+#else
     ble_gap_adv_stop();
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -1039,6 +1126,15 @@ void bt_mesh_gatts_conn_cb_deregister(void)
     bt_mesh_gatts_conn_cb = NULL;
 }

+struct bt_mesh_conn_cb * bt_mesh_gatts_conn_cb_current()
+{
+    return bt_mesh_gatts_conn_cb;
+}
+
+int (*bt_mesh_gap_event_cb(void))(struct ble_gap_event *event, void *arg) {
+    return gap_event_cb;
+}
+
 static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle)
 {
     struct bt_mesh_gatt_service *svc = NULL;
@@ -1717,6 +1813,10 @@ void gatt_register_cb(struct ble_gatt_register_ctxt *ctxt,
     }
 }

+__attribute__((weak)) void esp_ble_mesh_init_gatts(void) {
+    // register your services here
+}
+
 void bt_mesh_gatt_init(void)
 {
     ble_att_set_preferred_mtu(BLE_ATT_MTU_DFLT);
@@ -1737,6 +1837,8 @@ void bt_mesh_gatt_init(void)
         rc = ble_gatts_add_svcs(svc_defs);
         assert(rc == 0);

+        esp_ble_mesh_init_gatts();
+
         ble_gatts_start();

         ble_gatts_svc_set_visibility(prov_svc_start_handle, 1);

Usage

#include "esp_ble_mesh_ble_api.h"
#include "mesh/adapter.h" // bt_mesh_gap_event_cb

#if MYNEWT_VAL(BLE_EXT_ADV)
static int
bleprph_gap_event(struct ble_gap_event *event, void *arg)
{
    bt_mesh_gap_event_cb()(event, arg);

    // your gap event handler here
    return 0;
}
#else
static struct bt_mesh_conn_cb * proxy_conn_cb;

static void gap_connected(struct bt_mesh_conn *conn, uint8_t status) {
    // feedback to ESP-BLE-MESH
    proxy_conn_cb->connected(conn, status);

    uint16_t conn_handle = conn->handle;
    printf("gap_connected: conn_handle=%d, status=%d\n", (int)conn_handle, (int)status);
}

static void gap_disconnected(struct bt_mesh_conn *conn, uint8_t reason) {
    // feedback to ESP-BLE-MESH
    proxy_conn_cb->disconnected(conn, reason);

    uint16_t conn_handle = conn->handle;
    printf("gap_disconnected: conn_handle=%d, reason=%d\n", (int)conn_handle, (int)reason);
}

struct bt_mesh_conn_cb conn_cb = {
    .connected = gap_connected,
    .disconnected = gap_disconnected,
};
#endif

// called in esp_ble_mesh_init()
void esp_ble_mesh_init_gatts(void) {
    int rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }

    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }
}

void  ble_on_sync_proc() {
    rc = esp_ble_mesh_init(&provision, &composition);
    if (rc != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", rc);
        return;
    }

#if MYNEWT_VAL(BLE_EXT_ADV)
        int err = ble_gap_ext_adv_configure(YOUR_ADV_IDX, &params, NULL,
                                   bleprph_gap_event, NULL);
        // ble_gap_ext_adv_set_data
        // ble_gap_ext_adv_start
#else
    // obtain the current gatt proxy callback for event feedback
    proxy_conn_cb = bt_mesh_gatts_conn_cb_current();

    // overwrite gap events callback
    bt_mesh_gatts_conn_cb_register(&conn_cb);
#endif

    esp_ble_mesh_node_prov_enable((esp_ble_mesh_prov_bearer_t)(ESP_BLE_MESH_PROV_ADV|ESP_BLE_MESH_PROV_GATT));
}
buganini commented 1 month ago

Here is a new patch to allow GATT Proxy + ESP-BLE-MESH working together, with less intrusive to the original code, but more flexible.

Changes

Patches

diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
index 1cb239a3ca..3f038ece24 100644
--- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
+++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
@@ -20,6 +20,8 @@
 extern "C" {
 #endif

+#define BLE_MESH_EXT_ADV_IDX 0
+
 /* BLE Mesh Max Connection Count */
 #ifdef CONFIG_BT_BLUEDROID_ENABLED
 #define BLE_MESH_MAX_CONN   CONFIG_BT_ACL_CONNECTIONS
@@ -799,6 +801,10 @@ int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16],
 int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16],
                        uint8_t enc_data[16]);

+int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg);
+int esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg);
+void esp_ble_mesh_init_gatts(void);
+
 enum {
     BLE_MESH_EXCEP_LIST_SUB_CODE_ADD = 0,
     BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE,
diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
index 0418b76c54..2e4f49c64e 100644
--- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
+++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
@@ -17,6 +17,7 @@
 #include "host/ble_hs.h"
 #include "host/ble_uuid.h"
 #include "host/ble_att.h"
+#include "host/ble_gap.h"
 #include "host/ble_gatt.h"
 #include "services/gap/ble_svc_gap.h"
 #include "services/gatt/ble_svc_gatt.h"
@@ -628,7 +629,11 @@ static int set_ad(const struct bt_mesh_adv_data *ad, size_t ad_len, uint8_t *buf
 #if CONFIG_BLE_MESH_NODE
 static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle);

-static int gap_event_cb(struct ble_gap_event *event, void *arg)
+__attribute__((weak)) int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg) {
+    return esp_ble_mesh_gap_event_cb(event, arg);
+}
+
+int esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
 {
     struct ble_gap_conn_desc desc;
     int rc;
@@ -771,12 +776,27 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg)
     return 0;
 }
 #else
-static int gap_event_cb(struct ble_gap_event *event, void *arg)
+static int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
 {
     return 0;
 }
 #endif /* CONFIG_BLE_MESH_NODE */

+#if MYNEWT_VAL(BLE_EXT_ADV)
+struct ble_gap_ext_adv_params params = {
+    .connectable = 1,
+    .scannable = 1,
+    .directed = 0,
+    .own_addr_type = BLE_OWN_ADDR_PUBLIC,
+    .primary_phy = BLE_HCI_LE_PHY_1M,
+    .secondary_phy = BLE_HCI_LE_PHY_2M,
+    .sid = BLE_MESH_EXT_ADV_IDX,
+    .itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .legacy_pdu = 1,
+};
+#endif
+
 /* APIs functions */
 int bt_le_adv_start(const struct bt_mesh_adv_param *param,
                     const struct bt_mesh_adv_data *ad, size_t ad_len,
@@ -800,6 +820,71 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param,
         return err;
     }

+#if MYNEWT_VAL(BLE_EXT_ADV)
+    if (ble_gap_ext_adv_active(BLE_MESH_EXT_ADV_IDX))
+    {
+        ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+    }
+
+    err = ble_gap_ext_adv_configure(BLE_MESH_EXT_ADV_IDX, &params, NULL,
+                                   weak_esp_ble_mesh_gap_event_cb, NULL);
+    if (err != 0) {
+        BT_ERR("Extended Advertising configure failed: err %d", err);
+        return err;
+    }
+
+    struct os_mbuf *data = os_msys_get_pkthdr(buf_len, 0);
+    if (data == NULL) {
+        BT_ERR("Extended Advertising configure failed: os_msys_get_pkthdr");
+        return -1;
+    }
+
+    err = os_mbuf_append(data, buf, buf_len);
+    if (err != 0) {
+        BT_ERR("Extended Advertising os_mbuf_append failed: err %d", err);
+        return err;
+    }
+
+    err = ble_gap_ext_adv_set_data(BLE_MESH_EXT_ADV_IDX, data);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_set_data failed: err %d", err);
+        return err;
+    }
+
+    if (sd && (param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) {
+        buf_len = 0;
+
+        err = set_ad(sd, sd_len, buf, &buf_len);
+        if (err) {
+            BT_ERR("set_ad failed: err %d", err);
+            return err;
+        }
+
+        struct os_mbuf *rsp_data = os_msys_get_pkthdr(buf_len, 0);
+        if (rsp_data == NULL) {
+            BT_ERR("Extended Advertising configure rsp failed: os_msys_get_pkthdr");
+            return -1;
+        }
+
+        err = os_mbuf_append(rsp_data, buf, buf_len);
+        if (err != 0) {
+            BT_ERR("Extended Advertising rsp os_mbuf_append failed: err %d", err);
+            return err;
+        }
+
+        err = ble_gap_ext_adv_rsp_set_data(BLE_MESH_EXT_ADV_IDX, rsp_data);
+        if (err != 0) {
+            BT_ERR("Extended Advertising ble_gap_ext_adv_rsp_set_data failed: err %d", err);
+            return err;
+        }
+    }
+
+    err = ble_gap_ext_adv_start(BLE_MESH_EXT_ADV_IDX, 0, 0);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_start failed: err %d", err);
+        return err;
+    }
+#else
     err = ble_gap_adv_set_data(buf, buf_len);
     if (err != 0) {
         BT_ERR("Advertising set failed: err %d", err);
@@ -856,7 +941,7 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param,

 again:
     err = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params,
-                            gap_event_cb, NULL);
+                            weak_esp_ble_mesh_gap_event_cb, NULL);
     if (err) {
         if (err == BLE_HS_EALREADY) {
             ble_gap_adv_stop();
@@ -866,6 +951,7 @@ again:
         BT_ERR("Advertising start failed: err %d", err);
         return err;
     }
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -941,7 +1027,7 @@ int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param,
     }

     err = ble_gap_adv_start(param->own_addr_type, &p_dir_bda, BLE_HS_FOREVER, &adv_params,
-                            gap_event_cb, NULL);
+                            weak_esp_ble_mesh_gap_event_cb, NULL);
     if (err) {
         BT_ERR("Failed to start advertising, err %d", err);
         return err;
@@ -959,7 +1045,12 @@ int bt_le_adv_stop(void)
         return 0;
     }
 #endif
+
+#if MYNEWT_VAL(BLE_EXT_ADV)
+    ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+#else
     ble_gap_adv_stop();
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -1717,6 +1808,10 @@ void gatt_register_cb(struct ble_gatt_register_ctxt *ctxt,
     }
 }

+__attribute__((weak)) void esp_ble_mesh_init_gatts(void) {
+    // register your services here
+}
+
 void bt_mesh_gatt_init(void)
 {
     ble_att_set_preferred_mtu(BLE_ATT_MTU_DFLT);
@@ -1737,6 +1832,8 @@ void bt_mesh_gatt_init(void)
         rc = ble_gatts_add_svcs(svc_defs);
         assert(rc == 0);

+        esp_ble_mesh_init_gatts();
+
         ble_gatts_start();

         ble_gatts_svc_set_visibility(prov_svc_start_handle, 1);

Usage

#include "esp_ble_mesh_ble_api.h"
#include "mesh/adapter.h" // bt_mesh_gap_event_cb

int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
{
    esp_ble_mesh_gap_event_cb(event, arg);

    // your gap event handler here
    return 0;
}

// called in esp_ble_mesh_init()
void esp_ble_mesh_init_gatts(void) {
    int rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }

    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }
}

void  ble_on_sync_proc() {
    rc = esp_ble_mesh_init(&provision, &composition);
    if (rc != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", rc);
        return;
    }

#if MYNEWT_VAL(BLE_EXT_ADV)
    int err = ble_gap_ext_adv_configure(YOUR_ADV_IDX, &params, NULL,
                                weak_esp_ble_mesh_gap_event_cb, NULL);
    // ble_gap_ext_adv_set_data
    // ble_gap_ext_adv_start
#else
    esp_ble_mesh_start_ble_advertising(&adv_param, &adv_data);
#endif

    esp_ble_mesh_node_prov_enable((esp_ble_mesh_prov_bearer_t)(ESP_BLE_MESH_PROV_ADV|ESP_BLE_MESH_PROV_GATT));
}
buganini commented 1 month ago

The new patch allows NimBLE GATT Peripheral + ESP-BLE-MESH to work together, with a less intrusive approach to the original code, but providing more flexibility.

Tested scenarios:

Changes

Patches

diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
index 1cb239a3ca..3f038ece24 100644
--- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
+++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h
@@ -20,6 +20,8 @@
 extern "C" {
 #endif

+#define BLE_MESH_EXT_ADV_IDX 0
+
 /* BLE Mesh Max Connection Count */
 #ifdef CONFIG_BT_BLUEDROID_ENABLED
 #define BLE_MESH_MAX_CONN   CONFIG_BT_ACL_CONNECTIONS
@@ -799,6 +801,10 @@ int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16],
 int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16],
                        uint8_t enc_data[16]);

+int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg);
+int esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg);
+void esp_ble_mesh_init_gatts(void);
+
 enum {
     BLE_MESH_EXCEP_LIST_SUB_CODE_ADD = 0,
     BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE,
diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
index 0418b76c54..a08838f923 100644
--- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
+++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c
@@ -17,6 +17,7 @@
 #include "host/ble_hs.h"
 #include "host/ble_uuid.h"
 #include "host/ble_att.h"
+#include "host/ble_gap.h"
 #include "host/ble_gatt.h"
 #include "services/gap/ble_svc_gap.h"
 #include "services/gatt/ble_svc_gatt.h"
@@ -424,6 +425,20 @@ static int disc_cb(struct ble_gap_event *event, void *arg)
         }
         break;
     }
+#if MYNEWT_VAL(BLE_EXT_ADV)
+    case BLE_GAP_EVENT_EXT_DISC: {
+        struct net_buf_simple buf = {0};
+
+        struct ble_gap_ext_disc_desc * desc = &event->ext_disc;
+        net_buf_simple_init_with_data(&buf, (void *)desc->data, desc->length_data);
+
+        if (bt_mesh_scan_dev_found_cb) {
+            /* TODO: Support Scan Response data length for NimBLE host */
+            bt_mesh_scan_dev_found_cb((bt_mesh_addr_t *)&desc->addr, desc->rssi, desc->legacy_event_type, &buf, 0);
+        }
+        break;
+    }
+#endif
 #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \
      CONFIG_BLE_MESH_GATT_PROXY_CLIENT
     case BLE_GAP_EVENT_CONNECT:
@@ -628,7 +643,11 @@ static int set_ad(const struct bt_mesh_adv_data *ad, size_t ad_len, uint8_t *buf
 #if CONFIG_BLE_MESH_NODE
 static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle);

-static int gap_event_cb(struct ble_gap_event *event, void *arg)
+__attribute__((weak)) int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg) {
+    return esp_ble_mesh_gap_event_cb(event, arg);
+}
+
+int esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
 {
     struct ble_gap_conn_desc desc;
     int rc;
@@ -771,12 +790,27 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg)
     return 0;
 }
 #else
-static int gap_event_cb(struct ble_gap_event *event, void *arg)
+static int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
 {
     return 0;
 }
 #endif /* CONFIG_BLE_MESH_NODE */

+#if MYNEWT_VAL(BLE_EXT_ADV)
+struct ble_gap_ext_adv_params params = {
+    .connectable = 0,
+    .scannable = 0,
+    .directed = 0,
+    .own_addr_type = BLE_OWN_ADDR_PUBLIC,
+    .primary_phy = BLE_HCI_LE_PHY_1M,
+    .secondary_phy = BLE_HCI_LE_PHY_2M,
+    .sid = BLE_MESH_EXT_ADV_IDX,
+    .itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN,
+    .legacy_pdu = 1,
+};
+#endif
+
 /* APIs functions */
 int bt_le_adv_start(const struct bt_mesh_adv_param *param,
                     const struct bt_mesh_adv_data *ad, size_t ad_len,
@@ -800,6 +834,74 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param,
         return err;
     }

+#if MYNEWT_VAL(BLE_EXT_ADV)
+    if (ble_gap_ext_adv_active(BLE_MESH_EXT_ADV_IDX))
+    {
+        ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+    }
+
+    params.connectable = (param->options & BLE_MESH_ADV_OPT_CONNECTABLE) ? 1 : 0;
+    params.scannable = sd_len > 0 ? 1 : 0;
+
+    err = ble_gap_ext_adv_configure(BLE_MESH_EXT_ADV_IDX, &params, NULL,
+                                   weak_esp_ble_mesh_gap_event_cb, NULL);
+    if (err != 0) {
+        BT_ERR("Extended Advertising configure failed: err %d", err);
+        return err;
+    }
+
+    struct os_mbuf *data = os_msys_get_pkthdr(buf_len, 0);
+    if (data == NULL) {
+        BT_ERR("Extended Advertising configure failed: os_msys_get_pkthdr");
+        return -1;
+    }
+
+    err = os_mbuf_append(data, buf, buf_len);
+    if (err != 0) {
+        BT_ERR("Extended Advertising os_mbuf_append failed: err %d", err);
+        return err;
+    }
+
+    err = ble_gap_ext_adv_set_data(BLE_MESH_EXT_ADV_IDX, data);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_set_data failed: err %d", err);
+        return err;
+    }
+
+    if (sd && (param->options & BLE_MESH_ADV_OPT_CONNECTABLE)) {
+        buf_len = 0;
+
+        err = set_ad(sd, sd_len, buf, &buf_len);
+        if (err) {
+            BT_ERR("set_ad failed: err %d", err);
+            return err;
+        }
+
+        struct os_mbuf *rsp_data = os_msys_get_pkthdr(buf_len, 0);
+        if (rsp_data == NULL) {
+            BT_ERR("Extended Advertising configure rsp failed: os_msys_get_pkthdr");
+            return -1;
+        }
+
+        err = os_mbuf_append(rsp_data, buf, buf_len);
+        if (err != 0) {
+            BT_ERR("Extended Advertising rsp os_mbuf_append failed: err %d", err);
+            return err;
+        }
+
+        err = ble_gap_ext_adv_rsp_set_data(BLE_MESH_EXT_ADV_IDX, rsp_data);
+        if (err != 0) {
+            BT_ERR("Extended Advertising ble_gap_ext_adv_rsp_set_data failed: err %d", err);
+            return err;
+        }
+    }
+
+    err = ble_gap_ext_adv_start(BLE_MESH_EXT_ADV_IDX, 0, 0);
+    if (err != 0) {
+        BT_ERR("Extended Advertising ble_gap_ext_adv_start failed: err %d", err);
+        return err;
+    }
+#else
     err = ble_gap_adv_set_data(buf, buf_len);
     if (err != 0) {
         BT_ERR("Advertising set failed: err %d", err);
@@ -856,7 +958,7 @@ int bt_le_adv_start(const struct bt_mesh_adv_param *param,

 again:
     err = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &adv_params,
-                            gap_event_cb, NULL);
+                            weak_esp_ble_mesh_gap_event_cb, NULL);
     if (err) {
         if (err == BLE_HS_EALREADY) {
             ble_gap_adv_stop();
@@ -866,6 +968,7 @@ again:
         BT_ERR("Advertising start failed: err %d", err);
         return err;
     }
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_set_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -941,7 +1044,7 @@ int bt_mesh_ble_adv_start(const struct bt_mesh_ble_adv_param *param,
     }

     err = ble_gap_adv_start(param->own_addr_type, &p_dir_bda, BLE_HS_FOREVER, &adv_params,
-                            gap_event_cb, NULL);
+                            weak_esp_ble_mesh_gap_event_cb, NULL);
     if (err) {
         BT_ERR("Failed to start advertising, err %d", err);
         return err;
@@ -959,7 +1062,12 @@ int bt_le_adv_stop(void)
         return 0;
     }
 #endif
+
+#if MYNEWT_VAL(BLE_EXT_ADV)
+    ble_gap_ext_adv_stop(BLE_MESH_EXT_ADV_IDX);
+#else
     ble_gap_adv_stop();
+#endif

 #if BLE_MESH_DEV
     bt_mesh_atomic_clear_bit(bt_mesh_dev.flags, BLE_MESH_DEV_ADVERTISING);
@@ -1717,6 +1825,10 @@ void gatt_register_cb(struct ble_gatt_register_ctxt *ctxt,
     }
 }

+__attribute__((weak)) void esp_ble_mesh_init_gatts(void) {
+    // register your services here
+}
+
 void bt_mesh_gatt_init(void)
 {
     ble_att_set_preferred_mtu(BLE_ATT_MTU_DFLT);
@@ -1737,6 +1849,8 @@ void bt_mesh_gatt_init(void)
         rc = ble_gatts_add_svcs(svc_defs);
         assert(rc == 0);

+        esp_ble_mesh_init_gatts();
+
         ble_gatts_start();

         ble_gatts_svc_set_visibility(prov_svc_start_handle, 1);

Usage

#include "esp_ble_mesh_ble_api.h"
#include "mesh/adapter.h" // bt_mesh_gap_event_cb

int weak_esp_ble_mesh_gap_event_cb(struct ble_gap_event *event, void *arg)
{
    esp_ble_mesh_gap_event_cb(event, arg);

    // your gap event handler here
    return 0;
}

// called in esp_ble_mesh_init()
void esp_ble_mesh_init_gatts(void) {
    int rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }

    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }
}

void  ble_on_sync_proc() {
    rc = esp_ble_mesh_init(&provision, &composition);
    if (rc != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", rc);
        return;
    }

#if MYNEWT_VAL(BLE_EXT_ADV)
    int err = ble_gap_ext_adv_configure(YOUR_ADV_IDX, &params, NULL,
                                weak_esp_ble_mesh_gap_event_cb, NULL);
    // ble_gap_ext_adv_set_data
    // ble_gap_ext_adv_start
#else
    esp_ble_mesh_start_ble_advertising(&adv_param, &adv_data);
#endif

    esp_ble_mesh_node_prov_enable((esp_ble_mesh_prov_bearer_t)(ESP_BLE_MESH_PROV_ADV|ESP_BLE_MESH_PROV_GATT));
}