From fdfe59d3690c8d0b5c39924d1e93917ab01809fc Mon Sep 17 00:00:00 2001 From: lly Date: Tue, 17 Sep 2019 16:32:27 +0800 Subject: [PATCH] ble_mesh: add low power node api and event --- components/bt/esp_ble_mesh/Kconfig.in | 11 ++-- .../api/core/esp_ble_mesh_low_power_api.c | 43 ++++++++++++- .../core/include/esp_ble_mesh_low_power_api.h | 34 ++++++++++ .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 35 +++++++++++ .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 49 +++++++++++++++ .../btc/include/btc_ble_mesh_prov.h | 12 ++++ .../mesh_core/include/mesh_main.h | 5 +- components/bt/esp_ble_mesh/mesh_core/lpn.c | 63 +++++++++++++------ 8 files changed, 226 insertions(+), 26 deletions(-) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index f00c5d25a6..f051988fe4 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -446,6 +446,7 @@ if BLE_MESH config BLE_MESH_LOW_POWER bool "Support for Low Power features" + select BLE_MESH_NODE help Enable this option to operate as a Low Power Node. If low power consumption is required by a node, this option should be enabled. And once the node @@ -456,7 +457,7 @@ if BLE_MESH config BLE_MESH_LPN_ESTABLISHMENT bool "Perform Friendship establishment using low power" - default y + default n help Perform the Friendship establishment using low power with the help of a reduced scan duty cycle. The downside of this is that the node may miss @@ -468,7 +469,7 @@ if BLE_MESH config BLE_MESH_LPN_AUTO bool "Automatically start looking for Friend nodes once provisioned" - default y + default n help Once provisioned, automatically enable LPN functionality and start looking for Friend nodes. If this option is disabled LPN mode needs to be manually @@ -487,8 +488,8 @@ if BLE_MESH before starting to look for Friend nodes. config BLE_MESH_LPN_RETRY_TIMEOUT - int "Retry timeout for Friend Requests" - default 8 + int "Retry timeout for Friend requests" + default 6 range 1 3600 help Time in seconds between Friend Requests, if a previous Friend Request did @@ -569,7 +570,7 @@ if BLE_MESH config BLE_MESH_LPN_GROUPS int "Number of groups the LPN can subscribe to" range 0 16384 - default 8 + default 2 help Maximum number of groups to which the LPN can subscribe. diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c index 07301c8377..8aa49c406d 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_low_power_api.c @@ -15,10 +15,51 @@ #include #include "btc/btc_task.h" -#include "btc/btc_manage.h" #include "esp_err.h" #include "btc_ble_mesh_prov.h" #include "esp_ble_mesh_defs.h" +esp_err_t esp_ble_mesh_lpn_enable(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_LPN_ENABLE; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_lpn_disable(bool force) +{ + btc_ble_mesh_prov_args_t arg = {0}; + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_LPN_DISABLE; + + arg.lpn_disable.force = force; + + 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_lpn_poll(void) +{ + btc_msg_t msg = {0}; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PROV; + msg.act = BTC_BLE_MESH_ACT_LPN_POLL; + + return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h index 48238c5eba..60957b6e69 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_low_power_api.h @@ -17,4 +17,38 @@ #include "esp_ble_mesh_defs.h" +/** + * @brief Enable BLE Mesh device LPN functionality. + * + * @note This API enables LPN functionality. Once called, the proper + * Friend Request will be sent. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_lpn_enable(void); + +/** + * @brief Disable BLE Mesh device LPN functionality. + * + * @param[in] force: when disabling LPN functionality, use this flag to indicate + * whether directly clear corresponding information or just + * send friend clear to disable it if friendship has already + * been established. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_lpn_disable(bool force); + +/** + * @brief LPN tries to poll messages from the Friend Node. + * + * @note Once called, Friend Poll will be sent to the Friend Node. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_lpn_poll(void); + #endif /* _ESP_BLE_MESH_LOW_POWER_API_H_ */ 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 39daedef0b..3ecdf05489 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 @@ -1241,6 +1241,11 @@ typedef enum { 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 */ + ESP_BLE_MESH_LPN_ENABLE_COMP_EVT, /*!< Enable Low Power Node completion event */ + ESP_BLE_MESH_LPN_DISABLE_COMP_EVT, /*!< Disable Low Power Node completion event */ + ESP_BLE_MESH_LPN_POLL_COMP_EVT, /*!< Low Power Node send Friend Poll completion event */ + ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT, /*!< Low Power Node establishes friendship event */ + ESP_BLE_MESH_LPN_FRIENDSHIP_TERMINATE_EVT, /*!< Low Power Node terminates friendship event */ ESP_BLE_MESH_PROV_EVT_MAX, } esp_ble_mesh_prov_cb_event_t; @@ -1531,6 +1536,36 @@ typedef union { uint8_t hops; /*!< Heartbeat hops (InitTTL - RxTTL + 1) */ uint16_t feature; /*!< Bit field of currently active features of the node */ } heartbeat_msg_recv; /*!< Event parameter of ESP_BLE_MESH_HEARTBEAT_MESSAGE_RECV_EVT */ + /* + * @brief ESP_BLE_MESH_LPN_ENABLE_COMP_EVT + */ + struct ble_mesh_lpn_enable_comp_param { + int err_code; /*!< Indicate the result of enabling LPN functionality */ + } lpn_enable_comp; /*!< Event parameter of ESP_BLE_MESH_LPN_ENABLE_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_LPN_DISABLE_COMP_EVT + */ + struct ble_mesh_lpn_disable_comp_param { + int err_code; /*!< Indicate the result of disabling LPN functionality */ + } lpn_disable_comp; /*!< Event parameter of ESP_BLE_MESH_LPN_DISABLE_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_LPN_POLL_COMP_EVT + */ + struct ble_mesh_lpn_poll_comp_param { + int err_code; /*!< Indicate the result of sending Friend Poll */ + } lpn_poll_comp; /*!< Event parameter of ESP_BLE_MESH_LPN_POLL_COMP_EVT */ + /** + * @brief ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT + */ + struct ble_mesh_lpn_friendship_establish_param { + uint16_t friend_addr; /*!< Friend Node unicast address */ + } lpn_friendship_establish; /*!< Event parameter of ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT */ + /** + * @brief ESP_BLE_MESH_LPN_FRIENDSHIP_TERMINATE_EVT + */ + struct ble_mesh_lpn_friendship_terminate_param { + uint16_t friend_addr; /*!< Friend Node unicast address */ + } lpn_friendship_terminate; /*!< Event parameter of ESP_BLE_MESH_LPN_FRIENDSHIP_TERMINATE_EVT */ } esp_ble_mesh_prov_cb_param_t; /** 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 cc1e366efb..4af196b9f7 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 @@ -567,6 +567,38 @@ static void btc_ble_mesh_reset_cb(void) } return; } + +#if CONFIG_BLE_MESH_LOW_POWER +static void btc_ble_mesh_lpn_cb(u16_t friend_addr, bool established) +{ + esp_ble_mesh_prov_cb_param_t mesh_param = {0}; + btc_msg_t msg = {0}; + bt_status_t ret; + u8_t act; + + LOG_DEBUG("%s", __func__); + + if (established) { + mesh_param.lpn_friendship_establish.friend_addr = friend_addr; + act = ESP_BLE_MESH_LPN_FRIENDSHIP_ESTABLISH_EVT; + } else { + mesh_param.lpn_friendship_terminate.friend_addr = friend_addr; + act = ESP_BLE_MESH_LPN_FRIENDSHIP_TERMINATE_EVT; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_PROV; + msg.act = act; + + ret = btc_transfer_context(&msg, &mesh_param, + sizeof(esp_ble_mesh_prov_cb_param_t), NULL); + if (ret != BT_STATUS_SUCCESS) { + LOG_ERROR("%s btc_transfer_context failed", __func__); + } + return; +} +#endif /* CONFIG_BLE_MESH_LOW_POWER */ + #endif /* CONFIG_BLE_MESH_NODE */ static void btc_ble_mesh_prov_register_complete_cb(int err_code) @@ -1224,6 +1256,9 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) arg->mesh_init.prov->link_close_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_link_close_cb; arg->mesh_init.prov->complete_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_complete_cb; arg->mesh_init.prov->reset_cb = (esp_ble_mesh_cb_t)btc_ble_mesh_reset_cb; +#if CONFIG_BLE_MESH_LOW_POWER + bt_mesh_lpn_set_cb(btc_ble_mesh_lpn_cb); +#endif /* CONFIG_BLE_MESH_LOW_POWER */ #endif /* CONFIG_BLE_MESH_NODE */ #if CONFIG_BLE_MESH_PROVISIONER arg->mesh_init.prov->provisioner_prov_read_oob_pub_key = (esp_ble_mesh_cb_t)btc_ble_mesh_provisioner_prov_read_oob_pub_key_cb; @@ -1440,6 +1475,20 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) bt_mesh_set_fast_prov_action(arg->set_fast_prov_action.action); break; #endif /* CONFIG_BLE_MESH_FAST_PROV */ +#if CONFIG_BLE_MESH_LOW_POWER + case BTC_BLE_MESH_ACT_LPN_ENABLE: + act = ESP_BLE_MESH_LPN_ENABLE_COMP_EVT; + param.lpn_enable_comp.err_code = bt_mesh_lpn_set(true, false); + break; + case BTC_BLE_MESH_ACT_LPN_DISABLE: + act = ESP_BLE_MESH_LPN_DISABLE_COMP_EVT; + param.lpn_disable_comp.err_code = bt_mesh_lpn_set(false, arg->lpn_disable.force); + break; + case BTC_BLE_MESH_ACT_LPN_POLL: + act = ESP_BLE_MESH_LPN_POLL_COMP_EVT; + param.lpn_poll_comp.err_code = bt_mesh_lpn_poll(); + break; +#endif /* CONFIG_BLE_MESH_LOW_POWER */ default: LOG_WARN("%s, Invalid msg->act %d", __func__, msg->act); return; 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 a179b62030..8c8e052426 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 @@ -55,6 +55,9 @@ typedef enum { BTC_BLE_MESH_ACT_PROVISIONER_ADD_LOCAL_NET_KEY, BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO, BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION, + BTC_BLE_MESH_ACT_LPN_ENABLE, + BTC_BLE_MESH_ACT_LPN_DISABLE, + BTC_BLE_MESH_ACT_LPN_POLL, } btc_ble_mesh_prov_act_t; typedef enum { @@ -156,6 +159,15 @@ typedef union { struct ble_mesh_set_fast_prov_action_args { uint8_t action; } set_fast_prov_action; + struct ble_mesh_lpn_enable_args { + /* RFU */ + } lpn_enable; + struct ble_mesh_lpn_disable_args { + bool force; + } lpn_disable; + struct ble_mesh_lpn_poll_args { + /* RFU */ + } lpn_poll; } btc_ble_mesh_prov_args_t; typedef union { diff --git a/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h b/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h index 1a79a7a1e7..d92adc6096 100644 --- a/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h +++ b/components/bt/esp_ble_mesh/mesh_core/include/mesh_main.h @@ -555,10 +555,13 @@ bool bt_mesh_iv_update(void); * from a battery power source. * * @param enable true to enable LPN functionality, false to disable it. + * @param force when disable LPN functionality, use this flag to indicate + * whether directly clear corresponding information or sending + * friend clear to disable it. * * @return Zero on success or (negative) error code otherwise. */ -int bt_mesh_lpn_set(bool enable); +int bt_mesh_lpn_set(bool enable, bool force); /** @brief Send out a Friend Poll message. * diff --git a/components/bt/esp_ble_mesh/mesh_core/lpn.c b/components/bt/esp_ble_mesh/mesh_core/lpn.c index ad301db06e..60b7320116 100644 --- a/components/bt/esp_ble_mesh/mesh_core/lpn.c +++ b/components/bt/esp_ble_mesh/mesh_core/lpn.c @@ -55,8 +55,11 @@ #define POLL_TIMEOUT_MAX(lpn) ((CONFIG_BLE_MESH_LPN_POLL_TIMEOUT * 100) - \ REQ_RETRY_DURATION(lpn)) -/* Update 4 to 20 for BQB test case MESH/NODE/FRND/LPM/BI-02-C */ -#define REQ_ATTEMPTS(lpn) (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 4) +/** + * 1. Should use 20 attempts for BQB test case MESH/NODE/FRND/LPM/BI-02-C. + * 2. We should use more specific value for each PollTimeout range. + */ +#define REQ_ATTEMPTS(lpn) (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 6) #define CLEAR_ATTEMPTS 2 @@ -72,7 +75,6 @@ static void (*lpn_cb)(u16_t friend_addr, bool established); -#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) static const char *state2str(int state) { switch (state) { @@ -94,17 +96,16 @@ static const char *state2str(int state) return "recv delay"; case BLE_MESH_LPN_WAIT_UPDATE: return "wait update"; + case BLE_MESH_LPN_OFFER_RECV: + return "offer recv"; default: return "(unknown)"; } } -#endif /* CONFIG_BLE_MESH_DEBUG_LOW_POWER */ static inline void lpn_set_state(int state) { -#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state)); -#endif bt_mesh.lpn.state = state; } @@ -149,6 +150,8 @@ static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *sourc static void clear_friendship(bool force, bool disable); +static bool scan_after_clear; + static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; @@ -156,7 +159,10 @@ static void friend_clear_sent(int err, void *user_data) /* We're switching away from Low Power behavior, so permanently * enable scanning. */ - bt_mesh_scan_enable(); + if (scan_after_clear == false) { + bt_mesh_scan_enable(); + scan_after_clear = true; + } lpn->req_attempts++; @@ -261,6 +267,11 @@ static void clear_friendship(bool force, bool disable) lpn_set_state(BLE_MESH_LPN_ENABLED); k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); + + scan_after_clear = false; + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } } static void friend_req_sent(u16_t duration, int err, void *user_data) @@ -269,6 +280,10 @@ static void friend_req_sent(u16_t duration, int err, void *user_data) if (err) { BT_ERR("%s, Sending Friend Request failed (err %d)", __func__, err); + + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_enable(); + } return; } @@ -322,10 +337,8 @@ static void req_sent(u16_t duration, int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; -#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) BT_DBG("req 0x%02x duration %u err %d state %s", lpn->sent_req, duration, err, state2str(lpn->state)); -#endif if (err) { BT_ERR("%s, Sending request failed (err %d)", __func__, err); @@ -346,6 +359,12 @@ static void req_sent(u16_t duration, int err, void *user_data) LPN_RECV_DELAY - SCAN_LATENCY); } else { lpn_set_state(BLE_MESH_LPN_OFFER_RECV); + /** + * Friend Update is replied by Friend Node with TTL set to 0 and Network + * Transmit set to 30ms which will cause the packet easy to be missed. + * Regarding this situation, here we can reduce the duration of receiving + * the first Friend Update. + */ k_delayed_work_submit(&lpn->timer, LPN_RECV_DELAY + duration + lpn->recv_win); @@ -404,7 +423,7 @@ void bt_mesh_lpn_disable(bool force) clear_friendship(force, true); } -int bt_mesh_lpn_set(bool enable) +int bt_mesh_lpn_set(bool enable, bool force) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; @@ -442,7 +461,7 @@ int bt_mesh_lpn_set(bool enable) k_delayed_work_cancel(&lpn->timer); lpn_set_state(BLE_MESH_LPN_DISABLED); } else { - bt_mesh_lpn_disable(false); + bt_mesh_lpn_disable(force); } } @@ -543,6 +562,10 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, lpn->counter++; + if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { + bt_mesh_scan_disable(); + } + return 0; } @@ -737,9 +760,7 @@ static void lpn_timeout(struct k_work *work) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; -#if defined(CONFIG_BLE_MESH_DEBUG_LOW_POWER) BT_DBG("state: %s", state2str(lpn->state)); -#endif switch (lpn->state) { case BLE_MESH_LPN_DISABLED: @@ -774,9 +795,15 @@ static void lpn_timeout(struct k_work *work) k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); break; case BLE_MESH_LPN_OFFER_RECV: - BT_WARN("No Friend Update received after the first Friend Poll"); - lpn->sent_req = 0U; - send_friend_poll(); + if (lpn->req_attempts < 6) { + BT_WARN("Retrying the first Friend Poll, %d attempts", lpn->req_attempts); + lpn->sent_req = 0U; + send_friend_poll(); + break; + } + + BT_ERR("Timeout waiting for the first Friend Update"); + clear_friendship(true, false); break; case BLE_MESH_LPN_ESTABLISHED: if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { @@ -1047,9 +1074,7 @@ int bt_mesh_lpn_init(void) k_delayed_work_init(&lpn->timer, lpn_timeout); if (lpn->state == BLE_MESH_LPN_ENABLED) { - if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { - bt_mesh_scan_disable(); - } else { + if (!IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { bt_mesh_scan_enable(); }