فهرست منبع

Merge branch 'bugfix/ble_mesh_local_model_sub_v4.1' into 'release/v4.1'

Bugfix/ble mesh local model sub (v4.1)

See merge request espressif/esp-idf!8983
Island 5 سال پیش
والد
کامیت
b7259bab36
22فایلهای تغییر یافته به همراه334 افزوده شده و 44 حذف شده
  1. 1 0
      components/bt/CMakeLists.txt
  2. 51 0
      components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c
  3. 32 0
      components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h
  4. 25 0
      components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h
  5. 0 2
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c
  6. 25 0
      components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c
  7. 14 0
      components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h
  8. 19 21
      components/bt/esp_ble_mesh/mesh_core/cfg_cli.c
  9. 2 0
      components/bt/esp_ble_mesh/mesh_core/include/mesh_access.h
  10. 121 0
      components/bt/esp_ble_mesh/mesh_core/local_operation.c
  11. 29 0
      components/bt/esp_ble_mesh/mesh_core/local_operation.h
  12. 1 1
      examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/fast_prov_client/main/main.c
  13. 1 1
      examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md
  14. 3 4
      examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/main.c
  15. 7 8
      examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/main/main.c
  16. 0 1
      examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_server/main/main.c
  17. 0 1
      examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/main/main.c
  18. 0 1
      examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_server/main/main.c
  19. 1 1
      examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_client_model.c
  20. 0 1
      examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_common.h
  21. 1 1
      examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_operation.c
  22. 1 1
      examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_server_model.c

+ 1 - 0
components/bt/CMakeLists.txt

@@ -361,6 +361,7 @@ if(CONFIG_BT_ENABLED)
                     "esp_ble_mesh/mesh_core/friend.c"
                     "esp_ble_mesh/mesh_core/health_cli.c"
                     "esp_ble_mesh/mesh_core/health_srv.c"
+                    "esp_ble_mesh/mesh_core/local_operation.c"
                     "esp_ble_mesh/mesh_core/lpn.c"
                     "esp_ble_mesh/mesh_core/main.c"
                     "esp_ble_mesh/mesh_core/net.c"

+ 51 - 0
components/bt/esp_ble_mesh/api/core/esp_ble_mesh_local_data_operation_api.c

@@ -75,3 +75,54 @@ const esp_ble_mesh_comp_t *esp_ble_mesh_get_composition_data(void)
     return btc_ble_mesh_comp_get();
 }
 
+esp_err_t esp_ble_mesh_model_subscribe_group_addr(uint16_t element_addr, uint16_t company_id,
+                                                  uint16_t model_id, uint16_t group_addr)
+{
+    btc_ble_mesh_prov_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr) ||
+        !ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_PROV;
+    msg.act = BTC_BLE_MESH_ACT_MODEL_SUBSCRIBE_GROUP_ADDR;
+
+    arg.model_sub_group_addr.element_addr = element_addr;
+    arg.model_sub_group_addr.company_id = company_id;
+    arg.model_sub_group_addr.model_id = model_id;
+    arg.model_sub_group_addr.group_addr = group_addr;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
+            == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}
+
+esp_err_t esp_ble_mesh_model_unsubscribe_group_addr(uint16_t element_addr, uint16_t company_id,
+                                                    uint16_t model_id, uint16_t group_addr)
+{
+    btc_ble_mesh_prov_args_t arg = {0};
+    btc_msg_t msg = {0};
+
+    if (!ESP_BLE_MESH_ADDR_IS_UNICAST(element_addr) ||
+        !ESP_BLE_MESH_ADDR_IS_GROUP(group_addr)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
+
+    msg.sig = BTC_SIG_API_CALL;
+    msg.pid = BTC_PID_PROV;
+    msg.act = BTC_BLE_MESH_ACT_MODEL_UNSUBSCRIBE_GROUP_ADDR;
+
+    arg.model_unsub_group_addr.element_addr = element_addr;
+    arg.model_unsub_group_addr.company_id = company_id;
+    arg.model_unsub_group_addr.model_id = model_id;
+    arg.model_unsub_group_addr.group_addr = group_addr;
+
+    return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
+            == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
+}

+ 32 - 0
components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_local_data_operation_api.h

@@ -108,6 +108,38 @@ esp_ble_mesh_model_t *esp_ble_mesh_find_sig_model(const esp_ble_mesh_elem_t *ele
  */
 const esp_ble_mesh_comp_t *esp_ble_mesh_get_composition_data(void);
 
+/**
+ * @brief        A local model of node or Provisioner subscribes a group address.
+ *
+ * @note         This function shall not be invoked before node is provisioned or Provisioner is enabled.
+ *
+ * @param[in]    element_addr: Unicast address of the element to which the model belongs.
+ * @param[in]    company_id: A 16-bit company identifier.
+ * @param[in]    model_id: A 16-bit model identifier.
+ * @param[in]    group_addr: The group address to be subscribed.
+ *
+ * @return       ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_model_subscribe_group_addr(uint16_t element_addr, uint16_t company_id,
+                                                  uint16_t model_id, uint16_t group_addr);
+
+/**
+ * @brief        A local model of node or Provisioner unsubscribes a group address.
+ *
+ * @note         This function shall not be invoked before node is provisioned or Provisioner is enabled.
+ *
+ * @param[in]    element_addr: Unicast address of the element to which the model belongs.
+ * @param[in]    company_id: A 16-bit company identifier.
+ * @param[in]    model_id: A 16-bit model identifier.
+ * @param[in]    group_addr: The subscribed group address.
+ *
+ * @return       ESP_OK on success or error code otherwise.
+ *
+ */
+esp_err_t esp_ble_mesh_model_unsubscribe_group_addr(uint16_t element_addr, uint16_t company_id,
+                                                    uint16_t model_id, uint16_t group_addr);
+
 #ifdef __cplusplus
 }
 #endif

+ 25 - 0
components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h

@@ -58,6 +58,9 @@ typedef uint8_t esp_ble_mesh_octet16_t[ESP_BLE_MESH_OCTET16_LEN];
 #define ESP_BLE_MESH_OCTET8_LEN     8
 typedef uint8_t esp_ble_mesh_octet8_t[ESP_BLE_MESH_OCTET8_LEN];
 
+/*!< Invalid Company ID */
+#define ESP_BLE_MESH_CID_NVAL                     0xFFFF
+
 #define ESP_BLE_MESH_ADDR_UNASSIGNED              0x0000
 #define ESP_BLE_MESH_ADDR_ALL_NODES               0xFFFF
 #define ESP_BLE_MESH_ADDR_PROXIES                 0xFFFC
@@ -844,6 +847,8 @@ typedef enum {
     ESP_BLE_MESH_PROXY_CLIENT_REMOVE_FILTER_ADDR_COMP_EVT,      /*!< Proxy Client remove filter address completion event */
     ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT,                /*!< Start BLE advertising completion event */
     ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT,                 /*!< Stop BLE advertising completion event */
+    ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT,           /*!< Local model subscribes group address completion event */
+    ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT,         /*!< Local model unsubscribes group address completion event */
     ESP_BLE_MESH_DEINIT_MESH_COMP_EVT,                          /*!< De-initialize BLE Mesh stack completion event */
     ESP_BLE_MESH_PROV_EVT_MAX,
 } esp_ble_mesh_prov_cb_event_t;
@@ -1326,6 +1331,26 @@ typedef union {
         int err_code;                           /*!< Indicate the result of stopping BLE advertising */
         uint8_t index;                          /*!< Index of the BLE advertising */
     } stop_ble_advertising_comp;                /*!< Event parameter of ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT */
+    /**
+     * @brief ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT
+     */
+    struct ble_mesh_model_sub_group_addr_comp_param {
+        int err_code;                           /*!< Indicate the result of local model subscribing group address */
+        uint16_t element_addr;                  /*!< Element address */
+        uint16_t company_id;                    /*!< Company ID */
+        uint16_t model_id;                      /*!< Model ID */
+        uint16_t group_addr;                    /*!< Group Address */
+    } model_sub_group_addr_comp;                /*!< Event parameters of ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT */
+    /**
+     * @brief ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT
+     */
+    struct ble_mesh_model_unsub_group_addr_comp_param {
+        int err_code;                           /*!< Indicate the result of local model unsubscribing group address */
+        uint16_t element_addr;                  /*!< Element address */
+        uint16_t company_id;                    /*!< Company ID */
+        uint16_t model_id;                      /*!< Model ID */
+        uint16_t group_addr;                    /*!< Group Address */
+    } model_unsub_group_addr_comp;              /*!< Event parameters of ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT */
     /**
      * @brief ESP_BLE_MESH_DEINIT_MESH_COMP_EVT
      */

+ 0 - 2
components/bt/esp_ble_mesh/btc/btc_ble_mesh_config_model.c

@@ -20,8 +20,6 @@
 #include "cfg_cli.h"
 #include "esp_ble_mesh_config_model_api.h"
 
-#define CID_NVAL 0xffff
-
 extern s32_t config_msg_timeout;
 
 /* Configuration Client Model related functions */

+ 25 - 0
components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c

@@ -44,6 +44,7 @@
 #include "time_scene_client.h"
 #include "client_common.h"
 #include "state_binding.h"
+#include "local_operation.h"
 
 #include "esp_ble_mesh_common_api.h"
 #include "esp_ble_mesh_provisioning_api.h"
@@ -1898,6 +1899,30 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg)
             bt_mesh_stop_ble_advertising(arg->stop_ble_advertising.index);
         break;
 #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */
+    case BTC_BLE_MESH_ACT_MODEL_SUBSCRIBE_GROUP_ADDR:
+        act = ESP_BLE_MESH_MODEL_SUBSCRIBE_GROUP_ADDR_COMP_EVT;
+        param.model_sub_group_addr_comp.element_addr = arg->model_sub_group_addr.element_addr;
+        param.model_sub_group_addr_comp.company_id = arg->model_sub_group_addr.company_id;
+        param.model_sub_group_addr_comp.model_id = arg->model_sub_group_addr.model_id;
+        param.model_sub_group_addr_comp.group_addr = arg->model_sub_group_addr.group_addr;
+        param.model_sub_group_addr_comp.err_code =
+            bt_mesh_model_subscribe_group_addr(arg->model_sub_group_addr.element_addr,
+                                               arg->model_sub_group_addr.company_id,
+                                               arg->model_sub_group_addr.model_id,
+                                               arg->model_sub_group_addr.group_addr);
+        break;
+    case BTC_BLE_MESH_ACT_MODEL_UNSUBSCRIBE_GROUP_ADDR:
+        act = ESP_BLE_MESH_MODEL_UNSUBSCRIBE_GROUP_ADDR_COMP_EVT;
+        param.model_unsub_group_addr_comp.element_addr = arg->model_unsub_group_addr.element_addr;
+        param.model_unsub_group_addr_comp.company_id = arg->model_unsub_group_addr.company_id;
+        param.model_unsub_group_addr_comp.model_id = arg->model_unsub_group_addr.model_id;
+        param.model_unsub_group_addr_comp.group_addr = arg->model_unsub_group_addr.group_addr;
+        param.model_unsub_group_addr_comp.err_code =
+            bt_mesh_model_unsubscribe_group_addr(arg->model_unsub_group_addr.element_addr,
+                                                 arg->model_unsub_group_addr.company_id,
+                                                 arg->model_unsub_group_addr.model_id,
+                                                 arg->model_unsub_group_addr.group_addr);
+        break;
     case BTC_BLE_MESH_ACT_DEINIT_MESH:
         act = ESP_BLE_MESH_DEINIT_MESH_COMP_EVT;
         param.deinit_mesh_comp.err_code = bt_mesh_deinit((struct bt_mesh_deinit_param *)&arg->mesh_deinit.param);

+ 14 - 0
components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h

@@ -70,6 +70,8 @@ typedef enum {
     BTC_BLE_MESH_ACT_PROXY_CLIENT_REMOVE_FILTER_ADDR,
     BTC_BLE_MESH_ACT_START_BLE_ADVERTISING,
     BTC_BLE_MESH_ACT_STOP_BLE_ADVERTISING,
+    BTC_BLE_MESH_ACT_MODEL_SUBSCRIBE_GROUP_ADDR,
+    BTC_BLE_MESH_ACT_MODEL_UNSUBSCRIBE_GROUP_ADDR,
     BTC_BLE_MESH_ACT_DEINIT_MESH,
 } btc_ble_mesh_prov_act_t;
 
@@ -249,6 +251,18 @@ typedef union {
     struct ble_mesh_stop_ble_advertising_args {
         uint8_t index;
     } stop_ble_advertising;
+    struct ble_mesh_model_sub_group_addr_args {
+        uint16_t element_addr;
+        uint16_t company_id;
+        uint16_t model_id;
+        uint16_t group_addr;
+    } model_sub_group_addr;
+    struct ble_mesh_model_unsub_group_addr_args {
+        uint16_t element_addr;
+        uint16_t company_id;
+        uint16_t model_id;
+        uint16_t group_addr;
+    } model_unsub_group_addr;
     struct ble_mesh_deinit_args {
         esp_ble_mesh_deinit_param_t param;
     } mesh_deinit;

+ 19 - 21
components/bt/esp_ble_mesh/mesh_core/cfg_cli.c

@@ -20,8 +20,6 @@
 #include "mesh_common.h"
 #include "cfg_cli.h"
 
-#define CID_NVAL 0xffff
-
 /* 2 byte dummy opcode for getting compile time buffer sizes. */
 #define DUMMY_2_BYTE_OP     BLE_MESH_MODEL_OP_2(0xff, 0xff)
 
@@ -384,7 +382,7 @@ static void mod_app_status(struct bt_mesh_model *model,
     if (buf->len >= 4) {
         status.cid = net_buf_simple_pull_le16(buf);
     } else {
-        status.cid = CID_NVAL;
+        status.cid = BLE_MESH_CID_NVAL;
     }
     status.mod_id = net_buf_simple_pull_le16(buf);
 
@@ -413,7 +411,7 @@ static void mod_pub_status(struct bt_mesh_model *model,
     if (buf->len >= 4) {
         status.cid = net_buf_simple_pull_le16(buf);
     } else {
-        status.cid = CID_NVAL;
+        status.cid = BLE_MESH_CID_NVAL;
     }
     status.mod_id = net_buf_simple_pull_le16(buf);
 
@@ -436,7 +434,7 @@ static void mod_sub_status(struct bt_mesh_model *model,
     if (buf->len >= 4) {
         status.cid = net_buf_simple_pull_le16(buf);
     } else {
-        status.cid = CID_NVAL;
+        status.cid = BLE_MESH_CID_NVAL;
     }
     status.mod_id = net_buf_simple_pull_le16(buf);
 
@@ -511,7 +509,7 @@ static void mod_sub_list(struct bt_mesh_model *model,
     if (ctx->recv_op == OP_MOD_SUB_LIST_VND) {
         list.cid = net_buf_simple_pull_le16(buf);
     } else {
-        list.cid = CID_NVAL;
+        list.cid = BLE_MESH_CID_NVAL;
     }
     list.mod_id = net_buf_simple_pull_le16(buf);
 
@@ -599,7 +597,7 @@ static void mod_app_list(struct bt_mesh_model *model,
     if (ctx->recv_op == OP_VND_MOD_APP_LIST) {
         list.cid = net_buf_simple_pull_le16(buf);
     } else {
-        list.cid = CID_NVAL;
+        list.cid = BLE_MESH_CID_NVAL;
     }
     list.mod_id = net_buf_simple_pull_le16(buf);
 
@@ -908,7 +906,7 @@ int bt_mesh_cfg_mod_app_bind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     bt_mesh_model_msg_init(&msg, OP_MOD_APP_BIND);
     net_buf_simple_add_le16(&msg, elem_addr);
     net_buf_simple_add_le16(&msg, mod_app_idx);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -932,7 +930,7 @@ static int mod_sub(u32_t op, struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     bt_mesh_model_msg_init(&msg, op);
     net_buf_simple_add_le16(&msg, elem_addr);
     net_buf_simple_add_le16(&msg, sub_addr);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -986,7 +984,7 @@ static int mod_sub_va(u32_t op, struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     bt_mesh_model_msg_init(&msg, op);
     net_buf_simple_add_le16(&msg, elem_addr);
     net_buf_simple_add_mem(&msg, label, 16);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1039,7 +1037,7 @@ int bt_mesh_cfg_mod_pub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
 
     bt_mesh_model_msg_init(&msg, OP_MOD_PUB_GET);
     net_buf_simple_add_le16(&msg, elem_addr);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1072,7 +1070,7 @@ int bt_mesh_cfg_mod_pub_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     net_buf_simple_add_u8(&msg, pub->ttl);
     net_buf_simple_add_u8(&msg, pub->period);
     net_buf_simple_add_u8(&msg, pub->transmit);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1221,7 +1219,7 @@ int bt_mesh_cfg_mod_pub_va_set(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     net_buf_simple_add_u8(&msg, pub->ttl);
     net_buf_simple_add_u8(&msg, pub->period);
     net_buf_simple_add_u8(&msg, pub->transmit);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1248,7 +1246,7 @@ int bt_mesh_cfg_mod_sub_del_all(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
 
     bt_mesh_model_msg_init(&msg, OP_MOD_SUB_DEL_ALL);
     net_buf_simple_add_le16(&msg, elem_addr);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1271,7 +1269,7 @@ static int mod_sub_get(u32_t op, struct bt_mesh_msg_ctx *ctx,
 
     bt_mesh_model_msg_init(&msg, op);
     net_buf_simple_add_le16(&msg, elem_addr);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1290,13 +1288,13 @@ int bt_mesh_cfg_mod_sub_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t
     if (!ctx || !ctx->addr) {
         return -EINVAL;
     }
-    return mod_sub_get(OP_MOD_SUB_GET, ctx, elem_addr, mod_id, CID_NVAL);
+    return mod_sub_get(OP_MOD_SUB_GET, ctx, elem_addr, mod_id, BLE_MESH_CID_NVAL);
 }
 
 int bt_mesh_cfg_mod_sub_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
                                 u16_t mod_id, u16_t cid)
 {
-    if (!ctx || !ctx->addr || cid == CID_NVAL) {
+    if (!ctx || !ctx->addr || cid == BLE_MESH_CID_NVAL) {
         return -EINVAL;
     }
     return mod_sub_get(OP_MOD_SUB_GET_VND, ctx, elem_addr, mod_id, cid);
@@ -1487,7 +1485,7 @@ int bt_mesh_cfg_mod_app_unbind(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
     bt_mesh_model_msg_init(&msg, OP_MOD_APP_UNBIND);
     net_buf_simple_add_le16(&msg, elem_addr);
     net_buf_simple_add_le16(&msg, app_idx);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1510,7 +1508,7 @@ static int mod_app_get(u32_t op, struct bt_mesh_msg_ctx *ctx,
 
     bt_mesh_model_msg_init(&msg, op);
     net_buf_simple_add_le16(&msg, elem_addr);
-    if (cid != CID_NVAL) {
+    if (cid != BLE_MESH_CID_NVAL) {
         net_buf_simple_add_le16(&msg, cid);
     }
     net_buf_simple_add_le16(&msg, mod_id);
@@ -1529,13 +1527,13 @@ int bt_mesh_cfg_mod_app_get(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr, u16_t
     if (!ctx || !ctx->addr) {
         return -EINVAL;
     }
-    return mod_app_get(OP_SIG_MOD_APP_GET, ctx, elem_addr, mod_id, CID_NVAL);
+    return mod_app_get(OP_SIG_MOD_APP_GET, ctx, elem_addr, mod_id, BLE_MESH_CID_NVAL);
 }
 
 int bt_mesh_cfg_mod_app_get_vnd(struct bt_mesh_msg_ctx *ctx, u16_t elem_addr,
                                 u16_t mod_id, u16_t cid)
 {
-    if (!ctx || !ctx->addr || cid == CID_NVAL) {
+    if (!ctx || !ctx->addr || cid == BLE_MESH_CID_NVAL) {
         return -EINVAL;
     }
     return mod_app_get(OP_VND_MOD_APP_GET, ctx, elem_addr, mod_id, cid);

+ 2 - 0
components/bt/esp_ble_mesh/mesh_core/include/mesh_access.h

@@ -26,6 +26,8 @@
 extern "C" {
 #endif
 
+#define BLE_MESH_CID_NVAL          0xFFFF
+
 #define BLE_MESH_ADDR_UNASSIGNED   0x0000
 #define BLE_MESH_ADDR_ALL_NODES    0xffff
 #define BLE_MESH_ADDR_PROXIES      0xfffc

+ 121 - 0
components/bt/esp_ble_mesh/mesh_core/local_operation.c

@@ -0,0 +1,121 @@
+/*  Bluetooth Mesh */
+
+/*
+ * Copyright (c) 2017 Intel Corporation
+ * Additional Copyright (c) 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <string.h>
+#include <errno.h>
+
+#include "mesh.h"
+#include "lpn.h"
+#include "crypto.h"
+#include "access.h"
+#include "foundation.h"
+#include "transport.h"
+#include "mesh_main.h"
+#include "settings.h"
+
+static struct bt_mesh_model *find_model(u16_t elem_addr, u16_t cid, u16_t mod_id)
+{
+    struct bt_mesh_elem *elem = NULL;
+
+    if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) {
+        BT_ERR("%s, Not a unicast address 0x%04x", __func__, elem_addr);
+        return NULL;
+    }
+
+    elem = bt_mesh_elem_find(elem_addr);
+    if (elem == NULL) {
+        BT_ERR("%s, No element found, addr 0x%04x", __func__, elem_addr);
+        return NULL;
+    }
+
+    if (cid == BLE_MESH_CID_NVAL) {
+        return bt_mesh_model_find(elem, mod_id);
+    } else {
+        return bt_mesh_model_find_vnd(elem, cid, mod_id);
+    }
+}
+
+int bt_mesh_model_subscribe_group_addr(u16_t elem_addr, u16_t cid,
+                                       u16_t mod_id, u16_t group_addr)
+{
+    struct bt_mesh_model *model = NULL;
+    int i;
+
+    model = find_model(elem_addr, cid, mod_id);
+    if (model == NULL) {
+        BT_ERR("Subscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id);
+        return -ENODEV;
+    }
+
+    if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) {
+        BT_ERR("Subscribe, not a group address 0x%04x", group_addr);
+        return -EINVAL;
+    }
+
+    if (bt_mesh_model_find_group(model, group_addr)) {
+        BT_INFO("Group address 0x%04x already exists", group_addr);
+        return 0;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(model->groups); i++) {
+        if (model->groups[i] == BLE_MESH_ADDR_UNASSIGNED) {
+            model->groups[i] = group_addr;
+
+            if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
+                bt_mesh_store_mod_sub(model);
+            }
+
+            if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) {
+                bt_mesh_lpn_group_add(group_addr);
+            }
+
+            BT_INFO("Subscribe group address 0x%04x", group_addr);
+            return 0;
+        }
+    }
+
+    BT_ERR("Subscribe, model sub is full!");
+    return -ENOMEM;
+}
+
+int bt_mesh_model_unsubscribe_group_addr(u16_t elem_addr, u16_t cid,
+                                         u16_t mod_id, u16_t group_addr)
+{
+    struct bt_mesh_model *model = NULL;
+    u16_t *match = NULL;
+
+    model = find_model(elem_addr, cid, mod_id);
+    if (model == NULL) {
+        BT_ERR("Unsubscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id);
+        return -ENODEV;
+    }
+
+    if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) {
+        BT_ERR("Unsubscribe, not a group address 0x%04x", group_addr);
+        return -EINVAL;
+    }
+
+    match = bt_mesh_model_find_group(model, group_addr);
+    if (match == NULL) {
+        BT_WARN("Group address 0x%04x not exists", group_addr);
+        return -EEXIST;
+    }
+
+    *match = BLE_MESH_ADDR_UNASSIGNED;
+
+    if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
+        bt_mesh_store_mod_sub(model);
+    }
+
+    if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) {
+        bt_mesh_lpn_group_del(&group_addr, 1);
+    }
+
+    BT_INFO("Unsubscribe group address 0x%04x", group_addr);
+    return 0;
+}

+ 29 - 0
components/bt/esp_ble_mesh/mesh_core/local_operation.h

@@ -0,0 +1,29 @@
+/*  Bluetooth Mesh */
+
+/*
+ * Copyright (c) 2017 Intel Corporation
+ * Additional Copyright (c) 2020 Espressif Systems (Shanghai) PTE LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _LOCAL_OPERATION_H_
+#define _LOCAL_OPERATION_H_
+
+#include "mesh_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int bt_mesh_model_subscribe_group_addr(u16_t elem_addr, u16_t mod_id,
+                                       u16_t cid, u16_t group_addr);
+
+int bt_mesh_model_unsubscribe_group_addr(u16_t elem_addr, u16_t cid,
+                                         u16_t mod_id, u16_t group_addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOCAL_OPERATION_H_ */

+ 1 - 1
examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/fast_prov_client/main/main.c

@@ -288,7 +288,7 @@ static void example_provisioning_callback(esp_ble_mesh_prov_cb_event_t event,
             esp_err_t err;
             prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx;
             err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
-                    ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
+                    ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL);
             if (err != ESP_OK) {
                 ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__);
                 return;

+ 1 - 1
examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/fast_prov_client/tutorial/BLE_Mesh_Fast_Prov_Client_Example_Walkthrough.md

@@ -101,7 +101,7 @@ To control the server model, the client model uses messages to control the serve
 ```c
 prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx;
 err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
-                                              ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
+                                              ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL);
 if (err != ESP_OK) {
     ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__);
     return;

+ 3 - 4
examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/main/main.c

@@ -25,7 +25,6 @@
 #define LED_ON              0x1
 
 #define CID_ESP             0x02E5
-#define CID_NVAL            0xFFFF
 
 #define PROV_OWN_ADDR       0x0001
 
@@ -323,7 +322,7 @@ static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
             esp_err_t err = 0;
             prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx;
             err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx,
-                    ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
+                    ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL);
             if (err != ESP_OK) {
                 ESP_LOGE(TAG, "Provisioner bind local model appkey failed");
                 return;
@@ -397,7 +396,7 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t
             set_state.model_app_bind.element_addr = node->unicast;
             set_state.model_app_bind.model_app_idx = prov_key.app_idx;
             set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV;
-            set_state.model_app_bind.company_id = CID_NVAL;
+            set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL;
             err = esp_ble_mesh_config_client_set_state(&common, &set_state);
             if (err) {
                 ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__);
@@ -463,7 +462,7 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t
             set_state.model_app_bind.element_addr = node->unicast;
             set_state.model_app_bind.model_app_idx = prov_key.app_idx;
             set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV;
-            set_state.model_app_bind.company_id = CID_NVAL;
+            set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL;
             err = esp_ble_mesh_config_client_set_state(&common, &set_state);
             if (err) {
                 ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__);

+ 7 - 8
examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/main/main.c

@@ -23,7 +23,6 @@
 #include "board.h"
 
 #define CID_ESP             0x02E5
-#define CID_NVAL            0xFFFF
 
 #define PROV_OWN_ADDR       0x0001
 
@@ -225,7 +224,7 @@ static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
         if (param->provisioner_add_app_key_comp.err_code == 0) {
             prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx;
             esp_err_t err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx,
-                                ESP_BLE_MESH_MODEL_ID_SENSOR_CLI, CID_NVAL);
+                                ESP_BLE_MESH_MODEL_ID_SENSOR_CLI, ESP_BLE_MESH_CID_NVAL);
             if (err != ESP_OK) {
                 ESP_LOGE(TAG, "Failed to bind AppKey to sensor client");
             }
@@ -334,31 +333,31 @@ static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t
             set.model_app_bind.element_addr = node->unicast_addr;
             set.model_app_bind.model_app_idx = prov_key.app_idx;
             set.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_SENSOR_SRV;
-            set.model_app_bind.company_id = CID_NVAL;
+            set.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL;
             err = esp_ble_mesh_config_client_set_state(&common, &set);
             if (err != ESP_OK) {
                 ESP_LOGE(TAG, "Failed to send Config Model App Bind");
                 return;
             }
             wait_model_id = ESP_BLE_MESH_MODEL_ID_SENSOR_SRV;
-            wait_cid = CID_NVAL;
+            wait_cid = ESP_BLE_MESH_CID_NVAL;
         } else if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND) {
             if (param->status_cb.model_app_status.model_id == ESP_BLE_MESH_MODEL_ID_SENSOR_SRV &&
-                param->status_cb.model_app_status.company_id == CID_NVAL) {
+                param->status_cb.model_app_status.company_id == ESP_BLE_MESH_CID_NVAL) {
                 example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
                 set.model_app_bind.element_addr = node->unicast_addr;
                 set.model_app_bind.model_app_idx = prov_key.app_idx;
                 set.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV;
-                set.model_app_bind.company_id = CID_NVAL;
+                set.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL;
                 err = esp_ble_mesh_config_client_set_state(&common, &set);
                 if (err) {
                     ESP_LOGE(TAG, "Failed to send Config Model App Bind");
                     return;
                 }
                 wait_model_id = ESP_BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV;
-                wait_cid = CID_NVAL;
+                wait_cid = ESP_BLE_MESH_CID_NVAL;
             } else if (param->status_cb.model_app_status.model_id == ESP_BLE_MESH_MODEL_ID_SENSOR_SETUP_SRV &&
-                param->status_cb.model_app_status.company_id == CID_NVAL) {
+                param->status_cb.model_app_status.company_id == ESP_BLE_MESH_CID_NVAL) {
                 ESP_LOGW(TAG, "Provision and config successfully");
             }
         }

+ 0 - 1
examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_server/main/main.c

@@ -24,7 +24,6 @@
 #include "board.h"
 
 #define CID_ESP     0x02E5
-#define CID_NVAL    0xFFFF
 
 /* Sensor Property ID */
 #define SENSOR_PROPERTY_ID_0        0x0056  /* Present Indoor Ambient Temperature */

+ 0 - 1
examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/main/main.c

@@ -23,7 +23,6 @@
 #include "board.h"
 
 #define CID_ESP             0x02E5
-#define CID_NVAL            0xFFFF
 
 #define PROV_OWN_ADDR       0x0001
 

+ 0 - 1
examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_server/main/main.c

@@ -25,7 +25,6 @@
 #include "ble_mesh_example_init.h"
 
 #define CID_ESP     0x02E5
-#define CID_NVAL    0xFFFF
 
 #define ESP_BLE_MESH_VND_MODEL_ID_CLIENT    0x0000
 #define ESP_BLE_MESH_VND_MODEL_ID_SERVER    0x0001

+ 1 - 1
examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_client_model.c

@@ -379,7 +379,7 @@ esp_err_t example_fast_prov_client_recv_status(esp_ble_mesh_model_t *model,
             return ESP_FAIL;
         }
         cli_model = example_find_model(esp_ble_mesh_get_primary_element_address(),
-                                       ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
+                                       ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL);
         if (!cli_model) {
             ESP_LOGE(TAG, "%s: Failed to get Generic OnOff Client Model info", __func__);
             return ESP_FAIL;

+ 0 - 1
examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_common.h

@@ -22,7 +22,6 @@
 #define LED_ON      0x01
 
 #define CID_ESP     0x02E5
-#define CID_NVAL    0xFFFF
 
 /* Fast Prov Model ID */
 #define ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI                 0x0000

+ 1 - 1
examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_operation.c

@@ -150,7 +150,7 @@ esp_ble_mesh_model_t *example_find_model(uint16_t element_addr, uint16_t model_i
         return NULL;
     }
 
-    if (company_id == CID_NVAL) {
+    if (company_id == ESP_BLE_MESH_CID_NVAL) {
         return esp_ble_mesh_find_sig_model(element, model_id);
     } else {
         return esp_ble_mesh_find_vendor_model(element, company_id, model_id);

+ 1 - 1
examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning/ble_mesh_fast_prov_server_model.c

@@ -62,7 +62,7 @@ esp_ble_mesh_cfg_srv_t *get_cfg_srv_user_data(void)
     esp_ble_mesh_model_t *model = NULL;
 
     model = example_find_model(esp_ble_mesh_get_primary_element_address(),
-                               ESP_BLE_MESH_MODEL_ID_CONFIG_SRV, CID_NVAL);
+                               ESP_BLE_MESH_MODEL_ID_CONFIG_SRV, ESP_BLE_MESH_CID_NVAL);
     if (!model) {
         ESP_LOGE(TAG, "%s: Failed to get config server model", __func__);
         return NULL;