From 729af3834649667db8cd1696ca4e30b968b10ace Mon Sep 17 00:00:00 2001 From: lly Date: Tue, 17 Sep 2019 19:30:35 +0800 Subject: [PATCH] ble_mesh: add separate advertising buffers for relay packets --- components/bt/esp_ble_mesh/Kconfig.in | 22 ++ components/bt/esp_ble_mesh/mesh_core/adv.c | 260 ++++++++++++++++++--- components/bt/esp_ble_mesh/mesh_core/adv.h | 20 +- components/bt/esp_ble_mesh/mesh_core/net.c | 26 +++ 4 files changed, 295 insertions(+), 33 deletions(-) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index e85be747e9..f00c5d25a6 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -422,6 +422,28 @@ if BLE_MESH be enabled or disabled by proper configuration messages. Disabling this option will let a node not support the Relay feature. + if BLE_MESH_RELAY + + config BLE_MESH_RELAY_ADV_BUF + bool "Use separate advertising buffers for relay packets" + default n + help + When selected, self-send packets will be put in a high-priority + queue and relay packets will be put in a low-priority queue. + + if BLE_MESH_RELAY_ADV_BUF + + config BLE_MESH_RELAY_ADV_BUF_COUNT + int "Number of advertising buffers for relay packets" + default 60 + range 6 256 + help + Number of advertising buffers for relay packets available. + + endif # BLE_MESH_RELAY_ADV_BUF + + endif # BLE_MESH_RELAY + config BLE_MESH_LOW_POWER bool "Support for Low Power features" help diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.c b/components/bt/esp_ble_mesh/mesh_core/adv.c index 05de517823..4a325d1e26 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.c +++ b/components/bt/esp_ble_mesh/mesh_core/adv.c @@ -55,7 +55,6 @@ #define ADV_STACK_SIZE 768 #endif -static xQueueHandle xBleMeshQueue; static const bt_mesh_addr_t *dev_addr; static const u8_t adv_type[] = { @@ -70,6 +69,27 @@ NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BLE_MESH_ADV_BUF_COUNT + 3 * CONFIG_BLE static struct bt_mesh_adv adv_pool[CONFIG_BLE_MESH_ADV_BUF_COUNT + 3 * CONFIG_BLE_MESH_PBA_SAME_TIME]; +static QueueHandle_t xBleMeshQueue; +#define BLE_MESH_QUEUE_SIZE 150 + +#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +NET_BUF_POOL_DEFINE(relay_adv_buf_pool, CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT, + BLE_MESH_ADV_DATA_SIZE, BLE_MESH_ADV_USER_DATA_SIZE, NULL); + +static struct bt_mesh_adv relay_adv_pool[CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT]; + +static QueueHandle_t xBleMeshRelayQueue; +#define BLE_MESH_RELAY_QUEUE_SIZE 150 + +static QueueSetHandle_t xBleMeshQueueSet; +#define BLE_MESH_QUEUE_SET_SIZE (BLE_MESH_QUEUE_SIZE + BLE_MESH_RELAY_QUEUE_SIZE) + +#define BLE_MESH_RELAY_TIME_INTERVAL K_SECONDS(6) +#define BLE_MESH_MAX_TIME_INTERVAL 0xFFFFFFFF + +static bool ignore_relay_packet(u32_t timestamp); +#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ + static struct bt_mesh_adv *adv_alloc(int id) { return &adv_pool[id]; @@ -147,48 +167,111 @@ static inline int adv_send(struct net_buf *buf) static void adv_thread(void *p) { - struct net_buf **buf = NULL; +#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) + QueueSetMemberHandle_t handle; +#endif bt_mesh_msg_t msg = {0}; - int status; - - BT_DBG("started"); + struct net_buf **buf; buf = (struct net_buf **)(&msg.arg); + BT_DBG("%s, starts", __func__); + while (1) { *buf = NULL; +#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) #if CONFIG_BLE_MESH_NODE if (IS_ENABLED(CONFIG_BLE_MESH_PROXY)) { xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); while (!(*buf)) { s32_t timeout; - BT_DBG("Proxy advertising start"); + BT_DBG("Mesh Proxy Advertising start"); timeout = bt_mesh_proxy_adv_start(); - BT_DBG("Proxy Advertising up to %d ms", timeout); + BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); xQueueReceive(xBleMeshQueue, &msg, timeout); - BT_DBG("Proxy advertising stop"); + BT_DBG("Mesh Proxy Advertising stop"); bt_mesh_proxy_adv_stop(); } } else { - xQueueReceive(xBleMeshQueue, &msg, (portTickType)portMAX_DELAY); + xQueueReceive(xBleMeshQueue, &msg, portMAX_DELAY); } #else - xQueueReceive(xBleMeshQueue, &msg, (portTickType)portMAX_DELAY); + xQueueReceive(xBleMeshQueue, &msg, portMAX_DELAY); #endif +#else /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ +#if CONFIG_BLE_MESH_NODE + if (IS_ENABLED(CONFIG_BLE_MESH_PROXY)) { + handle = xQueueSelectFromSet(xBleMeshQueueSet, K_NO_WAIT); + if (handle) { + if (uxQueueMessagesWaiting(xBleMeshQueue)) { + xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); + } else if (uxQueueMessagesWaiting(xBleMeshRelayQueue)) { + xQueueReceive(xBleMeshRelayQueue, &msg, K_NO_WAIT); + } + } else { + while (!(*buf)) { + s32_t timeout; + BT_DBG("Mesh Proxy Advertising start"); + timeout = bt_mesh_proxy_adv_start(); + BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); + handle = xQueueSelectFromSet(xBleMeshQueueSet, timeout); + BT_DBG("Mesh Proxy Advertising stop"); + bt_mesh_proxy_adv_stop(); + if (handle) { + if (uxQueueMessagesWaiting(xBleMeshQueue)) { + xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); + } else if (uxQueueMessagesWaiting(xBleMeshRelayQueue)) { + xQueueReceive(xBleMeshRelayQueue, &msg, K_NO_WAIT); + } + } + } + } + } else { + handle = xQueueSelectFromSet(xBleMeshQueueSet, portMAX_DELAY); + if (handle) { + if (uxQueueMessagesWaiting(xBleMeshQueue)) { + xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); + } else if (uxQueueMessagesWaiting(xBleMeshRelayQueue)) { + xQueueReceive(xBleMeshRelayQueue, &msg, K_NO_WAIT); + } + } + } +#else + handle = xQueueSelectFromSet(xBleMeshQueueSet, portMAX_DELAY); + if (handle) { + if (uxQueueMessagesWaiting(xBleMeshQueue)) { + xQueueReceive(xBleMeshQueue, &msg, K_NO_WAIT); + } else if (uxQueueMessagesWaiting(xBleMeshRelayQueue)) { + xQueueReceive(xBleMeshRelayQueue, &msg, K_NO_WAIT); + } + } +#endif +#endif /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ - if (!(*buf)) { + if (*buf == NULL) { continue; } /* busy == 0 means this was canceled */ if (BLE_MESH_ADV(*buf)->busy) { BLE_MESH_ADV(*buf)->busy = 0U; - status = adv_send(*buf); - if (status) { - if (xQueueSendToFront(xBleMeshQueue, &msg, K_NO_WAIT) != pdTRUE) { - BT_ERR("%s, xQueueSendToFront failed", __func__); +#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) + if (adv_send(*buf)) { + BT_WARN("%s, Failed to send adv packet", __func__); + } +#else /* !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ + if (msg.relay && ignore_relay_packet(msg.timestamp)) { + /* If the interval between "current time - msg.timestamp" is bigger than + * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. + */ + BT_DBG("%s, Ignore relay packet", __func__); + net_buf_unref(*buf); + } else { + if (adv_send(*buf)) { + BT_WARN("%s, Failed to send adv packet", __func__); } } +#endif } else { net_buf_unref(*buf); } @@ -198,13 +281,6 @@ static void adv_thread(void *p) } } -void bt_mesh_adv_update(void) -{ - BT_DBG("%s", __func__); - bt_mesh_msg_t msg = {0}; - bt_mesh_task_post(&msg, 0); -} - struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool, bt_mesh_adv_alloc_t get_id, enum bt_mesh_adv_type type, @@ -244,17 +320,35 @@ struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit, xmit, timeout); } -void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout) +static void bt_mesh_unref_buf(bt_mesh_msg_t *msg) +{ + struct net_buf *buf; + + if (msg->arg) { + buf = (struct net_buf *)msg->arg; + BLE_MESH_ADV(buf)->busy = 0U; + net_buf_unref(buf); + } + + return; +} + +static void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout) { BT_DBG("%s", __func__); if (xQueueSend(xBleMeshQueue, msg, timeout) != pdTRUE) { - BT_ERR("%s, Failed to post msg to queue", __func__); + BT_ERR("%s, Failed to send item to queue", __func__); + bt_mesh_unref_buf(msg); } } void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, void *cb_data) { + bt_mesh_msg_t msg = { + .relay = false, + }; + BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, bt_hex(buf->data, buf->len)); @@ -262,11 +356,117 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, BLE_MESH_ADV(buf)->cb_data = cb_data; BLE_MESH_ADV(buf)->busy = 1U; - bt_mesh_msg_t msg = {0}; msg.arg = (void *)net_buf_ref(buf); bt_mesh_task_post(&msg, portMAX_DELAY); } +void bt_mesh_adv_update(void) +{ + bt_mesh_msg_t msg = { + .relay = false, + .arg = NULL, + }; + + BT_DBG("%s", __func__); + + bt_mesh_task_post(&msg, K_NO_WAIT); +} + +#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +static bool ignore_relay_packet(u32_t timestamp) +{ + u32_t now = k_uptime_get_32(); + u32_t interval; + + if (now > timestamp) { + interval = now - timestamp; + } else if (now == timestamp) { + interval = BLE_MESH_MAX_TIME_INTERVAL; + } else { + interval = BLE_MESH_MAX_TIME_INTERVAL - (timestamp - now) + 1; + } + + return (interval >= BLE_MESH_RELAY_TIME_INTERVAL) ? true : false; +} + +static struct bt_mesh_adv *relay_adv_alloc(int id) +{ + return &relay_adv_pool[id]; +} + +struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, u8_t xmit, + s32_t timeout) +{ + return bt_mesh_adv_create_from_pool(&relay_adv_buf_pool, relay_adv_alloc, type, + xmit, timeout); +} + +static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout) +{ + QueueSetMemberHandle_t handle; + bt_mesh_msg_t old_msg = {0}; + + BT_DBG("%s", __func__); + + if (xQueueSend(xBleMeshRelayQueue, msg, timeout) == pdTRUE) { + return; + } + + /** + * If failed to send packet to the relay queue(queue is full), we will + * remove the oldest packet in the queue and put the new one into it. + */ + handle = xQueueSelectFromSet(xBleMeshQueueSet, K_NO_WAIT); + if (handle && uxQueueMessagesWaiting(xBleMeshRelayQueue)) { + BT_DBG("%s, Full queue, remove the oldest relay packet", __func__); + /* Remove the oldest relay packet from queue */ + if (xQueueReceive(xBleMeshRelayQueue, &old_msg, K_NO_WAIT) != pdTRUE) { + BT_ERR("%s, Failed to remove item from queue", __func__); + bt_mesh_unref_buf(msg); + return; + } + /* Unref buf used for the oldest relay packet */ + bt_mesh_unref_buf(&old_msg); + /* Send the latest relay packet to queue */ + if (xQueueSend(xBleMeshRelayQueue, msg, K_NO_WAIT) != pdTRUE) { + BT_ERR("%s, Failed to send item to relay queue", __func__); + bt_mesh_unref_buf(msg); + return; + } + } else { + BT_WARN("%s, Empty queue, but failed to send the relay packet", __func__); + bt_mesh_unref_buf(msg); + } +} + +void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data, u16_t src, u16_t dst) +{ + bt_mesh_msg_t msg = { + .relay = true, + }; + + BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, + bt_hex(buf->data, buf->len)); + + BLE_MESH_ADV(buf)->cb = cb; + BLE_MESH_ADV(buf)->cb_data = cb_data; + BLE_MESH_ADV(buf)->busy = 1U; + + msg.arg = (void *)net_buf_ref(buf); + msg.src = src; + msg.dst = dst; + msg.timestamp = k_uptime_get_32(); + /* Use K_NO_WAIT here, if xBleMeshRelayQueue is full return immediately */ + ble_mesh_relay_task_post(&msg, K_NO_WAIT); +} + +u16_t bt_mesh_get_stored_relay_count(void) +{ + return (u16_t)uxQueueMessagesWaiting(xBleMeshRelayQueue); +} +#endif /* #if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ + const bt_mesh_addr_t *bt_mesh_pba_get_addr(void) { return dev_addr; @@ -385,8 +585,16 @@ static void bt_mesh_scan_cb(const bt_mesh_addr_t *addr, s8_t rssi, void bt_mesh_adv_init(void) { - xBleMeshQueue = xQueueCreate(150, sizeof(bt_mesh_msg_t)); + xBleMeshQueue = xQueueCreate(BLE_MESH_QUEUE_SIZE, sizeof(bt_mesh_msg_t)); configASSERT(xBleMeshQueue); +#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) + xBleMeshRelayQueue = xQueueCreate(BLE_MESH_RELAY_QUEUE_SIZE, sizeof(bt_mesh_msg_t)); + configASSERT(xBleMeshRelayQueue); + xBleMeshQueueSet = xQueueCreateSet(BLE_MESH_QUEUE_SET_SIZE); + configASSERT(xBleMeshQueueSet); + xQueueAddToSet(xBleMeshQueue, xBleMeshQueueSet); + xQueueAddToSet(xBleMeshRelayQueue, xBleMeshQueueSet); +#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */ int ret = xTaskCreatePinnedToCore(adv_thread, "BLE_Mesh_ADV_Task", 3072, NULL, configMAX_PRIORITIES - 7, NULL, ADV_TASK_CORE); configASSERT(ret == pdTRUE); diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.h b/components/bt/esp_ble_mesh/mesh_core/adv.h index b827af59ea..10b62e2fd5 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.h +++ b/components/bt/esp_ble_mesh/mesh_core/adv.h @@ -21,11 +21,11 @@ #define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) typedef struct bt_mesh_msg { - uint8_t sig; //event signal - uint8_t aid; //application id - uint8_t pid; //profile id - uint8_t act; //profile action, defined in seprerate header files - void *arg; //param for btc function or function param + bool relay; /* Flag indicates if the packet is a relayed one */ + void *arg; /* Pointer to the struct net_buf */ + u16_t src; /* Source address for relay packets */ + u16_t dst; /* Destination address for relay packets */ + u32_t timestamp; /* Timestamp recorded when the relay packet is posted to queue */ } bt_mesh_msg_t; enum bt_mesh_adv_type { @@ -73,6 +73,14 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, const bt_mesh_addr_t *bt_mesh_pba_get_addr(void); +struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, u8_t xmit, + s32_t timeout); + +void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data, u16_t src, u16_t dst); + +u16_t bt_mesh_get_stored_relay_count(void); + void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); @@ -81,6 +89,4 @@ int bt_mesh_scan_enable(void); int bt_mesh_scan_disable(void); -void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout); - #endif /* _ADV_H_ */ diff --git a/components/bt/esp_ble_mesh/mesh_core/net.c b/components/bt/esp_ble_mesh/mesh_core/net.c index 63d875f35c..22eee3b5dd 100644 --- a/components/bt/esp_ble_mesh/mesh_core/net.c +++ b/components/bt/esp_ble_mesh/mesh_core/net.c @@ -89,6 +89,10 @@ struct bt_mesh_net bt_mesh = { static u32_t dup_cache[4]; static int dup_cache_next; +#if defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) +#define BLE_MESH_MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) +#endif + static bool check_dup(struct net_buf_simple *data) { const u8_t *tail = net_buf_simple_tail(data); @@ -1202,7 +1206,25 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, transmit = bt_mesh_net_transmit_get(); } + /** + * When the node tries to relay a Segment ACK message, in this case + * the corresponding segment packets (if exist) can be removed from + * the relay queue. + */ + +#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, transmit, K_NO_WAIT); +#else + /** + * Check if the number of relay packets in queue is too large, if so + * use minimum relay retransmit value for later relay packets. + */ + if (bt_mesh_get_stored_relay_count() >= BLE_MESH_MAX_STORED_RELAY_COUNT) { + transmit = BLE_MESH_TRANSMIT(0, 20); + } + buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_DATA, transmit, K_NO_WAIT); +#endif + if (!buf) { BT_ERR("%s, Out of relay buffers", __func__); return; @@ -1256,7 +1278,11 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, } if (relay_to_adv(rx->net_if)) { +#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) bt_mesh_adv_send(buf, NULL, NULL); +#else + bt_mesh_relay_adv_send(buf, NULL, NULL, rx->ctx.addr, rx->ctx.recv_dst); +#endif } done: