ble_mesh: add low power node api and event

pull/3650/merge
lly 2019-09-17 16:32:27 +08:00
rodzic afc00fb5f5
commit fdfe59d369
8 zmienionych plików z 226 dodań i 26 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -15,10 +15,51 @@
#include <stdint.h>
#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);
}

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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;
/**

Wyświetl plik

@ -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;

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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.
*

Wyświetl plik

@ -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();
}