Просмотр исходного кода

ble_mesh: add separate advertising buffers for relay packets

lly 6 лет назад
Родитель
Сommit
4702cd1b51

+ 22 - 0
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

+ 234 - 26
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, 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
-        xQueueReceive(xBleMeshQueue, &msg, (portTickType)portMAX_DELAY);
+        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);

+ 13 - 7
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_ */

+ 26 - 0
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: