diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index 21765cc81b..cdb867b026 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -195,6 +195,28 @@ if BLE_MESH This option specifies how many application keys the Provisioner can have. Indeed, this value decides the number of the application keys which can be added by a Provisioner. + config BLE_MESH_PROVISIONER_RECV_HB + bool "Support receiving Heartbeat messages" + default n + help + When this option is enabled, Provisioner can call specific functions to enable + or disable receiving Heartbeat messages and notify them to the application layer. + + if BLE_MESH_PROVISIONER_RECV_HB + + config BLE_MESH_PROVISIONER_RECV_HB_FILTER_SIZE + int "Maximum number of filter entries for receiving Heartbeat messages" + default 3 + range 1 1000 + help + This option specifies how many heartbeat filter entries Provisioner supports. + The heartbeat filter (acceptlist or rejectlist) entries are used to store a + list of SRC and DST which can be used to decide if a heartbeat message will + be processed and notified to the application layer by Provisioner. + Note: The filter is an empty rejectlist by default. + + endif # BLE_MESH_PROVISIONER_RECV_HB + endif # BLE_MESH_PROVISIONER # Virtual option enabled whenever Generic Provisioning layer is needed diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c index 32d9cc30cd..d4cc1d74c1 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_networking_api.c @@ -528,6 +528,76 @@ const uint8_t *esp_ble_mesh_provisioner_get_local_net_key(uint16_t net_idx) { return bt_mesh_provisioner_local_net_key_get(net_idx); } + +#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB +esp_err_t esp_ble_mesh_provisioner_recv_heartbeat(bool enable) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + 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_PROVISIONER_ENABLE_HEARTBEAT_RECV; + + arg.enable_heartbeat_recv.enable = enable; + + 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_provisioner_set_heartbeat_filter_type(uint8_t type) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (type > ESP_BLE_MESH_HEARTBEAT_FILTER_REJECTLIST) { + 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_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE; + + arg.set_heartbeat_filter_type.type = type; + + 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_provisioner_set_heartbeat_filter_info(uint8_t op, esp_ble_mesh_heartbeat_filter_info_t *info) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (op > ESP_BLE_MESH_HEARTBEAT_FILTER_REMOVE || info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_src) && + !ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_dst) && + !ESP_BLE_MESH_ADDR_IS_GROUP(info->hb_dst)) { + 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_PROVISIONER_SET_HEARTBEAT_FILTER_INFO; + + arg.set_heartbeat_filter_info.op = op; + arg.set_heartbeat_filter_info.hb_src = info->hb_src; + arg.set_heartbeat_filter_info.hb_dst = info->hb_dst; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */ + #endif /* CONFIG_BLE_MESH_PROVISIONER */ #if (CONFIG_BLE_MESH_FAST_PROV) diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h index 86db8a1dab..dd880fa25a 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_networking_api.h @@ -413,6 +413,66 @@ esp_err_t esp_ble_mesh_provisioner_update_local_net_key(const uint8_t net_key[16 */ const uint8_t *esp_ble_mesh_provisioner_get_local_net_key(uint16_t net_idx); +/** + * @brief This function is called by Provisioner to enable or disable receiving + * heartbeat messages. + * + * @note If enabling receiving heartbeat message successfully, the filter will + * be an empty rejectlist by default, which means all heartbeat messages + * received by the Provisioner will be reported to the application layer. + * + * @param[in] enable: Enable or disable receiving heartbeat messages. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_recv_heartbeat(bool enable); + +/** + * @brief This function is called by Provisioner to set the heartbeat filter type. + * + * @note 1. If the filter type is not the same with the current value, then all the + * filter entries will be cleaned. + * 2. If the previous type is rejectlist, and changed to acceptlist, then the + * filter will be an empty acceptlist, which means no heartbeat messages + * will be reported. Users need to add SRC or DST into the filter entry, + * then heartbeat messages from the SRC or to the DST will be reported. + * + * @param[in] type: Heartbeat filter type (acceptlist or rejectlist). + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_type(uint8_t type); + +/** + * @brief This function is called by Provisioner to add or remove a heartbeat filter entry. + * + * @note 1. If the operation is "ADD", the "hb_src" can be set to the SRC (can only be a + * unicast address) of heartbeat messages, and the "hb_dst" can be set to the + * DST (unicast address or group address), at least one of them needs to be set. + * - If only one of them is set, the filter entry will only use the configured + * SRC or DST to filter heartbeat messages. + * - If both of them are set, the SRC and DST will both be used to decide if a + * heartbeat message will be handled. + * - If SRC or DST already exists in some filter entry, then the corresponding + * entry will be cleaned firstly, then a new entry will be allocated to store + * the information. + * 2. If the operation is "REMOVE", the "hb_src" can be set to the SRC (can only be + * a unicast address) of heartbeat messages, and the "hb_dst" can be set to the + * DST (unicast address or group address), at least one of them needs to be set. + * - The filter entry with the same SRC or DST will be removed. + * + * @param[in] op: Add or REMOVE + * @param[in] info: Heartbeat filter entry information, including: + * hb_src - Heartbeat source address; + * hb_dst - Heartbeat destination address; + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_info(uint8_t op, esp_ble_mesh_heartbeat_filter_info_t *info); + /** * @brief This function is called to get fast provisioning application key. * diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index c2216a4bf9..71ae994932 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -801,6 +801,20 @@ typedef struct { uint8_t scan_rsp_data[31]; /*!< Scan response data */ } esp_ble_mesh_ble_adv_data_t; +/*!< Provisioner heartbeat filter type */ +#define ESP_BLE_MESH_HEARTBEAT_FILTER_ACCEPTLIST 0x00 +#define ESP_BLE_MESH_HEARTBEAT_FILTER_REJECTLIST 0x01 + +/*!< Provisioner heartbeat filter operation */ +#define ESP_BLE_MESH_HEARTBEAT_FILTER_ADD 0x00 +#define ESP_BLE_MESH_HEARTBEAT_FILTER_REMOVE 0x01 + +/** Context of Provisioner heartbeat filter information to be set */ +typedef struct { + uint16_t hb_src; /*!< Heartbeat source address (unicast address) */ + uint16_t hb_dst; /*!< Heartbeat destination address (unicast address or group address) */ +} esp_ble_mesh_heartbeat_filter_info_t; + /*!< This enum value is the event of node/provisioner/fast provisioning */ typedef enum { ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, /*!< Initialize BLE Mesh provisioning capabilities and internal data information completion event */ @@ -852,6 +866,10 @@ typedef enum { ESP_BLE_MESH_PROVISIONER_STORE_NODE_COMP_DATA_COMP_EVT, /*!< Provisioner store node composition data completion event */ ESP_BLE_MESH_PROVISIONER_DELETE_NODE_WITH_UUID_COMP_EVT, /*!< Provisioner delete node with uuid completion event */ ESP_BLE_MESH_PROVISIONER_DELETE_NODE_WITH_ADDR_COMP_EVT, /*!< Provisioner delete node with unicast address completion event */ + ESP_BLE_MESH_PROVISIONER_ENABLE_HEARTBEAT_RECV_COMP_EVT, /*!< Provisioner start to receive heartbeat message completion event */ + ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT, /*!< Provisioner set the heartbeat filter type completion event */ + ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT, /*!< Provisioner set the heartbeat filter information completion event */ + ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT, /*!< Provisioner receive heartbeat message event */ ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT, /*!< Set fast provisioning information (e.g. unicast address range, net_idx, etc.) completion event */ ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, /*!< Set fast provisioning action completion event */ ESP_BLE_MESH_HEARTBEAT_MESSAGE_RECV_EVT, /*!< Receive Heartbeat message event */ @@ -1219,6 +1237,41 @@ typedef union { int err_code; /*!< Indicate the result of deleting node with unicast address by the Provisioner */ uint16_t unicast_addr; /*!< Node unicast address */ } provisioner_delete_node_with_addr_comp; /*!< Event parameter of ESP_BLE_MESH_PROVISIONER_DELETE_NODE_WITH_ADDR_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_ENABLE_HEARTBEAT_RECV_COMP_EVT + */ + struct { + int err_code; /*!< Indicate the result of enabling/disabling to receive heartbeat messages by the Provisioner */ + bool enable; /*!< Indicate enabling or disabling receiving heartbeat messages */ + } provisioner_enable_heartbeat_recv_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_ENABLE_HEARTBEAT_RECV_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT + */ + struct { + int err_code; /*!< Indicate the result of setting the heartbeat filter type by the Provisioner */ + uint8_t type; /*!< Type of the filter used for receiving heartbeat messages */ + } provisioner_set_heartbeat_filter_type_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT + */ + struct { + int err_code; /*!< Indicate the result of setting the heartbeat filter address by the Provisioner */ + uint8_t op; /*!< Operation (add, remove, clean) */ + uint16_t hb_src; /*!< Heartbeat source address */ + uint16_t hb_dst; /*!< Heartbeat destination address */ + } provisioner_set_heartbeat_filter_info_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT + */ + struct { + uint16_t hb_src; /*!< Heartbeat source address */ + uint16_t hb_dst; /*!< Heartbeat destination address */ + uint8_t init_ttl; /*!< Heartbeat InitTTL */ + uint8_t rx_ttl; /*!< Heartbeat RxTTL */ + uint8_t hops; /*!< Heartbeat hops (InitTTL - RxTTL + 1) */ + uint16_t feature; /*!< Bit field of currently active features of the node */ + int8_t rssi; /*!< RSSI of the heartbeat message */ + } provisioner_recv_heartbeat; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT */ /** * @brief ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 2a87d7a26f..ab03be5fb7 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -820,9 +820,29 @@ const esp_ble_mesh_node_t **btc_ble_mesh_provisioner_get_node_table_entry(void) { return (const esp_ble_mesh_node_t **)bt_mesh_provisioner_get_node_table_entry(); } + +#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB +static void btc_ble_mesh_provisioner_recv_heartbeat_cb(u16_t hb_src, u16_t hb_dst, + u8_t init_ttl, u8_t rx_ttl, + u8_t hops, u16_t feat, s8_t rssi) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + + mesh_param.provisioner_recv_heartbeat.hb_src = hb_src; + mesh_param.provisioner_recv_heartbeat.hb_dst = hb_dst; + mesh_param.provisioner_recv_heartbeat.init_ttl = init_ttl; + mesh_param.provisioner_recv_heartbeat.rx_ttl = rx_ttl; + mesh_param.provisioner_recv_heartbeat.hops = hops; + mesh_param.provisioner_recv_heartbeat.feature = feat; + mesh_param.provisioner_recv_heartbeat.rssi = rssi; + + btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT); +} +#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */ + #endif /* CONFIG_BLE_MESH_PROVISIONER */ -static void btc_ble_mesh_heartbeat_msg_recv_cb(u8_t hops, u16_t feature) +static void btc_ble_mesh_node_recv_heartbeat_cb(u8_t hops, u16_t feature) { esp_ble_mesh_prov_cb_param_t mesh_param = {0}; @@ -1197,7 +1217,7 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_cfg_srv_cb; struct bt_mesh_cfg_srv *srv = (struct bt_mesh_cfg_srv *)model->user_data; if (srv) { - srv->hb_sub.func = btc_ble_mesh_heartbeat_msg_recv_cb; + srv->hb_sub.func = btc_ble_mesh_node_recv_heartbeat_cb; } break; } @@ -1997,6 +2017,31 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) param.provisioner_delete_node_with_addr_comp.err_code = bt_mesh_provisioner_delete_node_with_node_addr(arg->delete_node_with_addr.unicast_addr); break; +#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB + case BTC_BLE_MESH_ACT_PROVISIONER_ENABLE_HEARTBEAT_RECV: + act = ESP_BLE_MESH_PROVISIONER_ENABLE_HEARTBEAT_RECV_COMP_EVT; + param.provisioner_enable_heartbeat_recv_comp.enable = arg->enable_heartbeat_recv.enable; + param.provisioner_enable_heartbeat_recv_comp.err_code = + bt_mesh_provisioner_recv_heartbeat(arg->enable_heartbeat_recv.enable ? + btc_ble_mesh_provisioner_recv_heartbeat_cb : NULL); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE: + act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT; + param.provisioner_set_heartbeat_filter_type_comp.type = arg->set_heartbeat_filter_type.type; + param.provisioner_set_heartbeat_filter_type_comp.err_code = + bt_mesh_provisioner_set_heartbeat_filter_type(arg->set_heartbeat_filter_type.type); + break; + case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO: + act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT; + param.provisioner_set_heartbeat_filter_info_comp.op = arg->set_heartbeat_filter_info.op; + param.provisioner_set_heartbeat_filter_info_comp.hb_src = arg->set_heartbeat_filter_info.hb_src; + param.provisioner_set_heartbeat_filter_info_comp.hb_dst = arg->set_heartbeat_filter_info.hb_dst; + param.provisioner_set_heartbeat_filter_info_comp.err_code = + bt_mesh_provisioner_set_heartbeat_filter_info(arg->set_heartbeat_filter_info.op, + arg->set_heartbeat_filter_info.hb_src, + arg->set_heartbeat_filter_info.hb_dst); + break; +#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */ #endif /* CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_FAST_PROV case BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO: diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h index 11e34c0192..06af8c2027 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_prov.h @@ -63,6 +63,9 @@ typedef enum { BTC_BLE_MESH_ACT_PROVISIONER_STORE_NODE_COMP_DATA, BTC_BLE_MESH_ACT_PROVISIONER_DELETE_NODE_WITH_UUID, BTC_BLE_MESH_ACT_PROVISIONER_DELETE_NODE_WITH_ADDR, + BTC_BLE_MESH_ACT_PROVISIONER_ENABLE_HEARTBEAT_RECV, + BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE, + BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO, BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO, BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION, BTC_BLE_MESH_ACT_LPN_ENABLE, @@ -217,6 +220,17 @@ typedef union { struct ble_mesh_provisioner_delete_node_with_addr_args { uint16_t unicast_addr; } delete_node_with_addr; + struct { + bool enable; + } enable_heartbeat_recv; + struct { + uint8_t type; + } set_heartbeat_filter_type; + struct { + uint8_t op; + uint16_t hb_src; + uint16_t hb_dst; + } set_heartbeat_filter_info; struct ble_mesh_set_fast_prov_info_args { uint16_t unicast_min; uint16_t unicast_max; diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c index 28e771d786..aa0e5a6fd3 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.c @@ -1544,4 +1544,235 @@ int bt_mesh_provisioner_store_node_info(struct bt_mesh_node *node) } #endif /* CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK */ +#if CONFIG_BLE_MESH_PROVISIONER_RECV_HB + +#define HEARTBEAT_FILTER_ACCEPTLIST 0x00 +#define HEARTBEAT_FILTER_REJECTLIST 0x01 + +#define HEARTBEAT_FILTER_ADD 0x00 +#define HEARTBEAT_FILTER_REMOVE 0x01 + +#define HEARTBEAT_FILTER_WITH_SRC BIT(0) +#define HEARTBEAT_FILTER_WITH_DST BIT(1) +#define HEARTBEAT_FILTER_WITH_BOTH (BIT(1) | BIT(0)) + +static struct heartbeat_recv { + struct heartbeat_filter { + u8_t type; /* Indicate if using src or dst or both to filter heartbeat messages */ + u16_t src; /* Heartbeat source address (unicast address) */ + u16_t dst; /* Heartbeat destination address (unicast address or group address) */ + } filter[CONFIG_BLE_MESH_PROVISIONER_RECV_HB_FILTER_SIZE]; + u8_t type; /* Heartbeat filter type */ + bt_mesh_heartbeat_recv_cb_t cb; /* Heartbeat receive callback */ +} hb_rx; + +int bt_mesh_provisioner_recv_heartbeat(bt_mesh_heartbeat_recv_cb_t cb) +{ + memset(&hb_rx, 0, sizeof(hb_rx)); + + /* Start with an empty rejectlist, which means all heartbeat messages will be reported */ + hb_rx.type = HEARTBEAT_FILTER_REJECTLIST; + hb_rx.cb = cb; + + return 0; +} + +int bt_mesh_provisioner_set_heartbeat_filter_type(u8_t type) +{ + if (type > HEARTBEAT_FILTER_REJECTLIST) { + BT_ERR("Invalid heartbeat filter type 0x%02x", type); + return -EINVAL; + } + + /* If the heartbeat filter type is different with previous one, + * clear the existing filter entries. + */ + if (hb_rx.type != type) { + memset(&hb_rx, 0, offsetof(struct heartbeat_recv, cb)); + hb_rx.type = type; + } + + return 0; +} + +static inline u8_t get_filter_addr_type(u16_t src, u16_t dst) +{ + if (BLE_MESH_ADDR_IS_UNICAST(src)) { + if (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) { + return HEARTBEAT_FILTER_WITH_BOTH; + } else { + return HEARTBEAT_FILTER_WITH_SRC; + } + } else { + return HEARTBEAT_FILTER_WITH_DST; + } +} + +static int hb_filter_alloc(u16_t src, u16_t dst) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { + struct heartbeat_filter *filter = &hb_rx.filter[i]; + + if (filter->src == BLE_MESH_ADDR_UNASSIGNED && + filter->dst == BLE_MESH_ADDR_UNASSIGNED) { + filter->type = get_filter_addr_type(src, dst); + filter->src = src; + filter->dst = dst; + return 0; + } + } + + BT_ERR("Heartbeat filter is full!"); + return -ENOMEM; +} + +static int hb_filter_add(u16_t src, u16_t dst) +{ + int i; + + if (!BLE_MESH_ADDR_IS_UNICAST(src) && + !BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) { + BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); + return -EINVAL; + } + + /* Check if filter entries with the same src or dst exist. */ + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { + struct heartbeat_filter *filter = &hb_rx.filter[i]; + + if ((BLE_MESH_ADDR_IS_UNICAST(src) && filter->src == src) || + ((BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) && + filter->dst == dst)) { + memset(filter, 0, sizeof(struct heartbeat_filter)); + } + } + + return hb_filter_alloc(src, dst); +} + +static int hb_filter_remove(u16_t src, u16_t dst) +{ + int i; + + if (!BLE_MESH_ADDR_IS_UNICAST(src) && + !BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) { + BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { + struct heartbeat_filter *filter = &hb_rx.filter[i]; + + if ((BLE_MESH_ADDR_IS_UNICAST(src) && filter->src == src) || + ((BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) && + filter->dst == dst)) { + memset(filter, 0, sizeof(struct heartbeat_filter)); + } + } + + return 0; +} + +int bt_mesh_provisioner_set_heartbeat_filter_info(u8_t op, u16_t src, u16_t dst) +{ + switch (op) { + case HEARTBEAT_FILTER_ADD: + return hb_filter_add(src, dst); + case HEARTBEAT_FILTER_REMOVE: + return hb_filter_remove(src, dst); + default: + BT_ERR("Invalid heartbeat filter opcode 0x%02x", op); + return -EINVAL; + } +} + +static bool filter_with_rejectlist(struct heartbeat_filter *filter, + u16_t hb_src, u16_t hb_dst) +{ + switch (filter->type) { + case HEARTBEAT_FILTER_WITH_SRC: + if (hb_src == filter->src) { + return true; + } + break; + case HEARTBEAT_FILTER_WITH_DST: + if (hb_dst == filter->dst) { + return true; + } + break; + case HEARTBEAT_FILTER_WITH_BOTH: + if (hb_src == filter->src && hb_dst == filter->dst) { + return true; + } + break; + default: + BT_WARN("Unknown filter addr type 0x%02x", filter->type); + break; + } + + return false; +} + +static bool filter_with_acceptlist(struct heartbeat_filter *filter, + u16_t hb_src, u16_t hb_dst) +{ + switch (filter->type) { + case HEARTBEAT_FILTER_WITH_SRC: + if (hb_src == filter->src) { + return false; + } + break; + case HEARTBEAT_FILTER_WITH_DST: + if (hb_dst == filter->dst) { + return false; + } + break; + case HEARTBEAT_FILTER_WITH_BOTH: + if (hb_src == filter->src && hb_dst == filter->dst) { + return false; + } + break; + default: + BT_WARN("Unknown filter addr type 0x%02x", filter->type); + return false; + } + + return true; +} + +void bt_mesh_provisioner_heartbeat(u16_t hb_src, u16_t hb_dst, + u8_t init_ttl, u8_t rx_ttl, + u8_t hops, u16_t feat, s8_t rssi) +{ + int i; + + if (hb_rx.cb == NULL) { + BT_DBG("Receiving heartbeat is not enabled"); + return; + } + + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { + struct heartbeat_filter *filter = &hb_rx.filter[i]; + + if (hb_rx.type == HEARTBEAT_FILTER_REJECTLIST) { + if (filter_with_rejectlist(filter, hb_src, hb_dst)) { + BT_DBG("Filtered by rejectlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); + return; + } + } else { + if (filter_with_acceptlist(filter, hb_src, hb_dst)) { + BT_DBG("Filtered by acceptlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); + return; + } + } + } + + if (hb_rx.cb) { + hb_rx.cb(hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi); + } +} +#endif /* CONFIG_BLE_MESH_PROVISIONER_RECV_HB */ + #endif /* CONFIG_BLE_MESH_PROVISIONER */ diff --git a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h index 5cc6490d57..f81d523ec1 100644 --- a/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h +++ b/components/bt/esp_ble_mesh/mesh_core/provisioner_main.h @@ -125,6 +125,20 @@ int bt_mesh_provisioner_local_net_key_del(u16_t net_idx, bool store); int bt_mesh_provisioner_bind_local_model_app_idx(u16_t elem_addr, u16_t mod_id, u16_t cid, u16_t app_idx); +typedef void (* bt_mesh_heartbeat_recv_cb_t)(u16_t hb_src, u16_t hb_dst, + u8_t init_ttl, u8_t rx_ttl, + u8_t hops, u16_t feat, s8_t rssi); + +int bt_mesh_provisioner_recv_heartbeat(bt_mesh_heartbeat_recv_cb_t cb); + +int bt_mesh_provisioner_set_heartbeat_filter_type(u8_t filter_type); + +int bt_mesh_provisioner_set_heartbeat_filter_info(u8_t op, u16_t src, u16_t dst); + +void bt_mesh_provisioner_heartbeat(u16_t hb_src, u16_t hb_dst, + u8_t init_ttl, u8_t rx_ttl, + u8_t hops, u16_t feat, s8_t rssi); + /* Provisioner print own element information */ int bt_mesh_print_local_composition_data(void); diff --git a/components/bt/esp_ble_mesh/mesh_core/transport.c b/components/bt/esp_ble_mesh/mesh_core/transport.c index c75cee2d34..4fbdd9fbf4 100644 --- a/components/bt/esp_ble_mesh/mesh_core/transport.c +++ b/components/bt/esp_ble_mesh/mesh_core/transport.c @@ -966,7 +966,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, return -EINVAL; } - if (rx->ctx.recv_dst != hb_sub_dst) { + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() && + rx->ctx.recv_dst != hb_sub_dst) { BT_WARN("Ignoring heartbeat to non-subscribed destination"); return 0; } @@ -980,7 +981,13 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, (hops == 1U) ? "" : "s", feat); - bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); + } else if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER_RECV_HB) && bt_mesh_is_provisioner_en()) { + bt_mesh_provisioner_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, + init_ttl, rx->ctx.recv_ttl, + hops, feat, rx->ctx.recv_rssi); + } return 0; } diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/sdkconfig.ci.rx_hb b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/sdkconfig.ci.rx_hb new file mode 100644 index 0000000000..cffc5e05fa --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_provisioner/sdkconfig.ci.rx_hb @@ -0,0 +1,16 @@ +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_BTDM_MODEM_SLEEP=n +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y +CONFIG_BT_BTU_TASK_STACK_SIZE=4512 + +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PROVISIONER_RECV_HB=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_SETTINGS=y +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y