From b1cded8e48f24295381ddaac87e3084aeba280f6 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Sun, 17 Jul 2022 14:17:52 +0800 Subject: [PATCH 01/17] component/bt: modify the implementation of osi_thread using freeRTOS queue --- components/bt/common/osi/thread.c | 136 ++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 24 deletions(-) diff --git a/components/bt/common/osi/thread.c b/components/bt/common/osi/thread.c index c26fc998c2..fa35e87b86 100644 --- a/components/bt/common/osi/thread.c +++ b/components/bt/common/osi/thread.c @@ -19,16 +19,27 @@ #include #include "osi/allocator.h" -#include "osi/fixed_queue.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" #include "osi/semaphore.h" #include "osi/thread.h" +struct work_item { + osi_thread_func_t func; + void *context; +}; + +struct work_queue { + QueueHandle_t queue; + size_t capacity; +}; + struct osi_thread { void *thread_handle; /*!< Store the thread object */ int thread_id; /*!< May for some OS, such as Linux */ bool stop; uint8_t work_queue_num; /*!< Work queue number */ - fixed_queue_t **work_queues; /*!< Point to queue array, and the priority inverse array index */ + struct work_queue **work_queues; /*!< Point to queue array, and the priority inverse array index */ osi_sem_t work_sem; osi_sem_t stop_sem; }; @@ -39,13 +50,90 @@ struct osi_thread_start_arg { int error; }; -typedef struct { - osi_thread_func_t func; - void *context; -} work_item_t; - static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100; +static struct work_queue *osi_work_queue_create(size_t capacity) +{ + if (capacity == 0) { + return NULL; + } + + struct work_queue *wq = (struct work_queue *)osi_malloc(sizeof(struct work_queue)); + if (wq != NULL) { + wq->queue = xQueueCreate(capacity, sizeof(struct work_item)); + if (wq->queue != 0) { + wq->capacity = capacity; + return wq; + } else { + osi_free(wq); + } + } + + return NULL; +} + +static void osi_work_queue_delete(struct work_queue *wq) +{ + if (wq != NULL) { + if (wq->queue != 0) { + vQueueDelete(wq->queue); + } + wq->queue = 0; + wq->capacity = 0; + osi_free(wq); + } + return; +} + +static bool osi_thead_work_queue_get(struct work_queue *wq, struct work_item *item) +{ + assert (wq != NULL); + assert (wq->queue != 0); + assert (item != NULL); + + if (pdTRUE == xQueueReceive(wq->queue, item, 0)) { + return true; + } else { + return false; + } +} + +static bool osi_thead_work_queue_put(struct work_queue *wq, const struct work_item *item, uint32_t timeout) +{ + assert (wq != NULL); + assert (wq->queue != 0); + assert (item != NULL); + + bool ret = true; + if (timeout == OSI_SEM_MAX_TIMEOUT) { + if (xQueueSend(wq->queue, item, portMAX_DELAY) != pdTRUE) { + ret = false; + } + } else { + if (xQueueSend(wq->queue, item, timeout / portTICK_PERIOD_MS) != pdTRUE) { + ret = false; + } + } + + return ret; +} + +static size_t osi_thead_work_queue_len(struct work_queue *wq) +{ + assert (wq != NULL); + assert (wq->queue != 0); + assert (wq->capacity != 0); + + size_t available_spaces = (size_t)uxQueueSpacesAvailable(wq->queue); + + if (available_spaces <= wq->capacity) { + return wq->capacity - available_spaces; + } else { + assert (0); + } + return 0; +} + static void osi_thread_run(void *arg) { struct osi_thread_start_arg *start = (struct osi_thread_start_arg *)arg; @@ -62,11 +150,10 @@ static void osi_thread_run(void *arg) break; } + struct work_item item; while (!thread->stop && idx < thread->work_queue_num) { - work_item_t *item = fixed_queue_dequeue(thread->work_queues[idx], 0); - if (item) { - item->func(item->context); - osi_free(item); + if (osi_thead_work_queue_get(thread->work_queues[idx], &item) == true) { + item.func(item.context); idx = 0; continue; } else { @@ -125,13 +212,13 @@ osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priorit thread->stop = false; thread->work_queue_num = work_queue_num; - thread->work_queues = (fixed_queue_t **)osi_malloc(sizeof(fixed_queue_t *) * work_queue_num); + thread->work_queues = (struct work_queue **)osi_malloc(sizeof(struct work_queue *) * work_queue_num); if (thread->work_queues == NULL) { goto _err; } for (int i = 0; i < thread->work_queue_num; i++) { - thread->work_queues[i] = fixed_queue_new(DEFAULT_WORK_QUEUE_CAPACITY); + thread->work_queues[i] = osi_work_queue_create(DEFAULT_WORK_QUEUE_CAPACITY); if (thread->work_queues[i] == NULL) { goto _err; } @@ -175,12 +262,14 @@ _err: for (int i = 0; i < thread->work_queue_num; i++) { if (thread->work_queues[i]) { - fixed_queue_free(thread->work_queues[i], osi_free_func); + osi_work_queue_delete(thread->work_queues[i]); } + thread->work_queues[i] = NULL; } if (thread->work_queues) { osi_free(thread->work_queues); + thread->work_queues = NULL; } if (thread->work_sem) { @@ -206,12 +295,14 @@ void osi_thread_free(osi_thread_t *thread) for (int i = 0; i < thread->work_queue_num; i++) { if (thread->work_queues[i]) { - fixed_queue_free(thread->work_queues[i], osi_free_func); + osi_work_queue_delete(thread->work_queues[i]); + thread->work_queues[i] = NULL; } } if (thread->work_queues) { osi_free(thread->work_queues); + thread->work_queues = NULL; } if (thread->work_sem) { @@ -235,15 +326,12 @@ bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context return false; } - work_item_t *item = (work_item_t *)osi_malloc(sizeof(work_item_t)); - if (item == NULL) { - return false; - } - item->func = func; - item->context = context; + struct work_item item; - if (fixed_queue_enqueue(thread->work_queues[queue_idx], item, timeout) == false) { - osi_free(item); + item.func = func; + item.context = context; + + if (osi_thead_work_queue_put(thread->work_queues[queue_idx], &item, timeout) == false) { return false; } @@ -273,5 +361,5 @@ int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx) return -1; } - return fixed_queue_length(thread->work_queues[wq_idx]); + return (int)(osi_thead_work_queue_len(thread->work_queues[wq_idx])); } From 26d201144210fc46013956a4d10f930ebc8c163e Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 1 Aug 2022 20:37:49 +0800 Subject: [PATCH 02/17] component/bt: make OSI thread workqueue length configurable through API reduce the length of workqueue1 for BTC and HCI task # Conflicts: # components/bt/common/osi/thread.c --- components/bt/common/btc/core/btc_task.c | 7 ++++++- components/bt/common/osi/include/osi/thread.h | 2 +- components/bt/common/osi/thread.c | 7 ++++--- components/bt/host/bluedroid/hci/hci_layer.c | 7 ++++++- components/bt/host/bluedroid/stack/btu/btu_init.c | 6 +++++- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 9579446817..840c858d18 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -71,6 +71,9 @@ #define BTC_TASK_STACK_SIZE (BT_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig #define BTC_TASK_NAME "BTC_TASK" #define BTC_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 6) +#define BTC_TASK_WORKQUEUE_NUM (2) +#define BTC_TASK_WORKQUEUE0_LEN (0) +#define BTC_TASK_WORKQUEUE1_LEN (5) osi_thread_t *btc_thread; @@ -398,7 +401,9 @@ error_exit:; bt_status_t btc_init(void) { - btc_thread = osi_thread_create(BTC_TASK_NAME, BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, 2); + const size_t workqueue_len[] = {BTC_TASK_WORKQUEUE0_LEN, BTC_TASK_WORKQUEUE1_LEN}; + btc_thread = osi_thread_create(BTC_TASK_NAME, BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE, + BTC_TASK_WORKQUEUE_NUM, workqueue_len); if (btc_thread == NULL) { return BT_STATUS_NOMEM; } diff --git a/components/bt/common/osi/include/osi/thread.h b/components/bt/common/osi/include/osi/thread.h index fdabed1cf6..d5f150f32a 100644 --- a/components/bt/common/osi/include/osi/thread.h +++ b/components/bt/common/osi/include/osi/thread.h @@ -48,7 +48,7 @@ typedef enum { * param work_queue_num: speicify queue number, the queue[0] has highest priority, and the priority is decrease by index * return : if create successfully, return thread handler; otherwise return NULL. */ -osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num); +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[]); /* * brief: Destroy a thread or task diff --git a/components/bt/common/osi/thread.c b/components/bt/common/osi/thread.c index fa35e87b86..5e0317219c 100644 --- a/components/bt/common/osi/thread.c +++ b/components/bt/common/osi/thread.c @@ -194,14 +194,14 @@ static void osi_thread_stop(osi_thread_t *thread) } //in linux, the stack_size, priority and core may not be set here, the code will be ignore the arguments -osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num) +osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[]) { int ret; struct osi_thread_start_arg start_arg = {0}; if (stack_size <= 0 || core < OSI_THREAD_CORE_0 || core > OSI_THREAD_CORE_AFFINITY || - work_queue_num <= 0) { + work_queue_num <= 0 || work_queue_len == NULL) { return NULL; } @@ -218,7 +218,8 @@ osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priorit } for (int i = 0; i < thread->work_queue_num; i++) { - thread->work_queues[i] = osi_work_queue_create(DEFAULT_WORK_QUEUE_CAPACITY); + size_t queue_len = work_queue_len[i] ? work_queue_len[i] : DEFAULT_WORK_QUEUE_CAPACITY; + thread->work_queues[i] = osi_work_queue_create(queue_len); if (thread->work_queues[i] == NULL) { goto _err; } diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 054cabb628..bd1ade792b 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -40,6 +40,9 @@ #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) #define HCI_HOST_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) #define HCI_HOST_TASK_NAME "hciT" +#define HCI_HOST_TASK_WORKQUEUE_NUM (2) +#define HCI_HOST_TASK_WORKQUEUE0_LEN (0) +#define HCI_HOST_TASK_WORKQUEUE1_LEN (5) typedef struct { uint16_t opcode; @@ -107,7 +110,9 @@ int hci_start_up(void) goto error; } - hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, 2); + const size_t workqueue_len[] = {HCI_HOST_TASK_WORKQUEUE0_LEN, HCI_HOST_TASK_WORKQUEUE1_LEN}; + hci_host_thread = osi_thread_create(HCI_HOST_TASK_NAME, HCI_HOST_TASK_STACK_SIZE, HCI_HOST_TASK_PRIO, HCI_HOST_TASK_PINNED_TO_CORE, + HCI_HOST_TASK_WORKQUEUE_NUM, workqueue_len); if (hci_host_thread == NULL) { return -2; } diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index 15b7fdbbc0..7699a471f0 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -48,6 +48,8 @@ #define BTU_TASK_STACK_SIZE (BT_BTU_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) #define BTU_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 5) #define BTU_TASK_NAME "BTU_TASK" +#define BTU_TASK_WORKQUEUE_NUM (2) +#define BTU_TASK_WORKQUEUE0_LEN (0) hash_map_t *btu_general_alarm_hash_map; osi_mutex_t btu_general_alarm_lock; @@ -181,7 +183,9 @@ void BTU_StartUp(void) osi_mutex_new(&btu_l2cap_alarm_lock); - btu_thread = osi_thread_create(BTU_TASK_NAME, BTU_TASK_STACK_SIZE, BTU_TASK_PRIO, BTU_TASK_PINNED_TO_CORE, 1); + const size_t workqueue_len[] = {BTU_TASK_WORKQUEUE0_LEN}; + btu_thread = osi_thread_create(BTU_TASK_NAME, BTU_TASK_STACK_SIZE, BTU_TASK_PRIO, BTU_TASK_PINNED_TO_CORE, + BTU_TASK_WORKQUEUE_NUM, workqueue_len); if (btu_thread == NULL) { goto error_exit; } From 0f4c9a47f104974ae79325e2c0bc75adf9b6600e Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Sun, 17 Jul 2022 16:18:01 +0800 Subject: [PATCH 03/17] component/bt: add new OSI utility "osi_event" to support the scenario that event need only to be handle once. --- components/bt/common/osi/include/osi/thread.h | 39 +++++++++ components/bt/common/osi/thread.c | 87 +++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/components/bt/common/osi/include/osi/thread.h b/components/bt/common/osi/include/osi/thread.h index d5f150f32a..c9be3375dd 100644 --- a/components/bt/common/osi/include/osi/thread.h +++ b/components/bt/common/osi/include/osi/thread.h @@ -28,6 +28,7 @@ #define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT struct osi_thread; +struct osi_event; typedef struct osi_thread osi_thread_t; @@ -88,4 +89,42 @@ const char *osi_thread_name(osi_thread_t *thread); */ int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx); +/* + * brief: Create an osi_event struct and register the handler function and its argument + * An osi_event is a kind of work that can be posted to the workqueue of osi_thread to process, + * but the work can have at most one instance the thread workqueue before it is processed. This + * allows the "single post, multiple data processing" jobs. + * param func: the handler to process the job + * param context: the argument to be passed to the handler function when the job is being processed + * return: NULL if no memory, otherwise a valid struct pointer + */ +struct osi_event *osi_event_create(osi_thread_func_t func, void *context); + +/* + * brief: Bind an osi_event to a specific work queue for an osi_thread. + * After binding is completed, a function call of API osi_thread_post_event will send a work + * to the workqueue of the thread, with specified queue index. + * param func: event: the pointer to osi_event that is created using osi_event_create + * param thread: the pointer to osi_thread that is created using osi_thread_create + * param queue_idx: the index of the workqueue of the specified osi_thread, with range starting from 0 to work_queue_num - 1 + * return: true if osi_event binds to the thread's workqueue successfully, otherwise false + */ +bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx); + +/* + * brief: Destroy the osi_event struct created by osi_event_create and free the allocated memory + * param event: the pointer to osi_event + */ +void osi_event_delete(struct osi_event* event); + +/* + * brief: try sending a work to the binded thread's workqueue, so that it can be handled by the worker thread + * param event: pointer to osi_event, created by osi_event_create + * param timeout: post timeout, OSI_THREAD_MAX_TIMEOUT means blocking forever, 0 means never blocking, others means block millisecond + * return: true if the message is enqueued to the thread workqueue, otherwise failed + * note: if the return value of function is false, it is the case that the workqueue of the thread is full, and users + * are expected to post the event sometime later to get the work handled. + */ +bool osi_thread_post_event(struct osi_event *event, uint32_t timeout); + #endif /* __THREAD_H__ */ diff --git a/components/bt/common/osi/thread.c b/components/bt/common/osi/thread.c index 5e0317219c..ba39659bd0 100644 --- a/components/bt/common/osi/thread.c +++ b/components/bt/common/osi/thread.c @@ -23,6 +23,7 @@ #include "freertos/queue.h" #include "osi/semaphore.h" #include "osi/thread.h" +#include "osi/mutex.h" struct work_item { osi_thread_func_t func; @@ -50,6 +51,14 @@ struct osi_thread_start_arg { int error; }; +struct osi_event { + struct work_item item; + osi_mutex_t lock; + uint16_t is_queued; + uint16_t queue_idx; + osi_thread_t *thread; +}; + static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100; static struct work_queue *osi_work_queue_create(size_t capacity) @@ -364,3 +373,81 @@ int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx) return (int)(osi_thead_work_queue_len(thread->work_queues[wq_idx])); } + + +struct osi_event *osi_event_create(osi_thread_func_t func, void *context) +{ + struct osi_event *event = osi_calloc(sizeof(struct osi_event)); + if (event != NULL) { + if (osi_mutex_new(&event->lock) == 0) { + event->item.func = func; + event->item.context = context; + return event; + } + osi_free(event); + } + + return NULL; +} + +void osi_event_delete(struct osi_event* event) +{ + if (event != NULL) { + osi_mutex_free(&event->lock); + memset(event, 0, sizeof(struct osi_event)); + osi_free(event); + } +} + +bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx) +{ + if (event == NULL || event->thread != NULL) { + return false; + } + + if (thread == NULL || queue_idx >= thread->work_queue_num) { + return false; + } + + event->thread = thread; + event->queue_idx = queue_idx; + + return true; +} + +static void osi_thread_generic_event_handler(void *context) +{ + struct osi_event *event = (struct osi_event *)context; + if (event != NULL && event->item.func != NULL) { + osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT); + event->is_queued = 0; + osi_mutex_unlock(&event->lock); + event->item.func(event->item.context); + } +} + +bool osi_thread_post_event(struct osi_event *event, uint32_t timeout) +{ + assert(event != NULL && event->thread != NULL); + assert(event->queue_idx >= 0 && event->queue_idx < event->thread->work_queue_num); + bool ret = false; + if (event->is_queued == 0) { + uint16_t acquire_cnt = 0; + osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT); + event->is_queued += 1; + acquire_cnt = event->is_queued; + osi_mutex_unlock(&event->lock); + + if (acquire_cnt == 1) { + ret = osi_thread_post(event->thread, osi_thread_generic_event_handler, event, event->queue_idx, timeout); + if (!ret) { + // clear "is_queued" when post failure, to allow for following event posts + osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT); + event->is_queued = 0; + osi_mutex_unlock(&event->lock); + } + } + } + + return ret; +} From 3c14e739f0c42d5ba968c99ba0753450239fd373 Mon Sep 17 00:00:00 2001 From: Karl Wang Date: Mon, 18 Jul 2022 01:55:37 +0800 Subject: [PATCH 04/17] component/bt: add new OSI utility "pkt_queue" which acts as a mutex-protected linked list, to be used as data queue between tasks --- components/bt/CMakeLists.txt | 1 + .../bt/common/osi/include/osi/pkt_queue.h | 88 +++++++++++ components/bt/common/osi/pkt_queue.c | 144 ++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 components/bt/common/osi/include/osi/pkt_queue.h create mode 100644 components/bt/common/osi/pkt_queue.c diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 52cabe65fd..6f23052610 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -36,6 +36,7 @@ if(CONFIG_BT_ENABLED) "common/osi/buffer.c" "common/osi/config.c" "common/osi/fixed_queue.c" + "common/osi/pkt_queue.c" "common/osi/future.c" "common/osi/hash_functions.c" "common/osi/hash_map.c" diff --git a/components/bt/common/osi/include/osi/pkt_queue.h b/components/bt/common/osi/include/osi/pkt_queue.h new file mode 100644 index 0000000000..96277c3e18 --- /dev/null +++ b/components/bt/common/osi/include/osi/pkt_queue.h @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _PKT_LIST_H_ +#define _PKT_LIST_H_ + +#include "sys/queue.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pkt_queue; + +typedef struct pkt_linked_item { + STAILQ_ENTRY(pkt_linked_item) next; + uint8_t data[]; +} pkt_linked_item_t; + +#define BT_PKT_LINKED_HDR_SIZE (sizeof (pkt_linked_item_t)) + +typedef void (*pkt_queue_free_cb)(pkt_linked_item_t *item); + +/* + * brief: create a pkt_queue instance. pkt_queue is a wrapper class of a FIFO implemented by single linked list. + * The enqueue and dequeue operations of the FIFO are protected against race conditions of multiple tasks + * return: NULL if not enough memory, otherwise a valid pointer + */ +struct pkt_queue *pkt_queue_create(void); + +/* + * brief: enqueue one item to the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * param item: the item to be enqueued to the FIFO + * return: true if enqueued successfully, false when the arguments passed in are invalid + */ +bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item); + +/* + * brief: dequeue one item for the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * return: pointer of type pkt_linked_item_t dequeued, NULL if the queue is empty or upon exception + */ +pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue); + +/* + * brief: get the pointer of the first item from the FIFO but not get it dequeued + * param queue: pkt_queue instance created using pkt_queue_create + * return: pointer of the first item in the FIFO, NULL if the FIFO is empty + */ +pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue); + +/* + * brief: retrieve the number of items existing in the FIFO + * param queue: pkt_queue instance created using pkt_queue_create + * return: total number of items in the FIFO + */ +size_t pkt_queue_length(const struct pkt_queue *queue); + +/* + * brief: retrieve the status whether the FIFO is empty + * param queue: pkt_queue instance created using pkt_queue_create + * return: false if the FIFO is not empty, otherwise true + */ +bool pkt_queue_is_empty(const struct pkt_queue *queue); + +/* + * brief: delete the item in the FIFO one by one + * param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default + */ +void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb); + +/* + * brief: delete the items in the FIFO and then destroy the pkt_queue instance. + * param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default + */ +void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/bt/common/osi/pkt_queue.c b/components/bt/common/osi/pkt_queue.c new file mode 100644 index 0000000000..81abd1f043 --- /dev/null +++ b/components/bt/common/osi/pkt_queue.c @@ -0,0 +1,144 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "osi/pkt_queue.h" +#include "osi/allocator.h" +#include "osi/mutex.h" + + +STAILQ_HEAD(pkt_queue_header, pkt_linked_item); + +struct pkt_queue { + osi_mutex_t lock; + size_t length; + struct pkt_queue_header header; +} pkt_queue_t; + +struct pkt_queue *pkt_queue_create(void) +{ + struct pkt_queue *queue = calloc(1, sizeof(struct pkt_queue)); + if (queue == NULL) { + return NULL; + } + if (osi_mutex_new(&queue->lock) != 0) { + osi_free(queue); + } + struct pkt_queue_header *p = &queue->header; + STAILQ_INIT(p); + + return queue; +} + +static void pkt_queue_cleanup(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + + struct pkt_queue_header *header = &queue->header; + pkt_linked_item_t *item = STAILQ_FIRST(header); + pkt_linked_item_t *tmp; + + pkt_queue_free_cb free_func = (free_cb != NULL) ? free_cb : (pkt_queue_free_cb)osi_free_func; + + while (item != NULL) { + tmp = STAILQ_NEXT(item, next); + free_func(item); + item = tmp; + queue->length--; + } + STAILQ_INIT(header); + queue->length = 0; +} + +void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + pkt_queue_cleanup(queue, free_cb); + osi_mutex_unlock(&queue->lock); +} + +void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + pkt_queue_cleanup(queue, free_cb); + osi_mutex_unlock(&queue->lock); + + osi_mutex_free(&queue->lock); + osi_free(queue); +} + +pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue) +{ + if (queue == NULL || queue->length == 0) { + return NULL; + } + + struct pkt_linked_item *item; + struct pkt_queue_header *header; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + header = &queue->header; + item = STAILQ_FIRST(header); + if (item != NULL) { + STAILQ_REMOVE_HEAD(header, next); + if (queue->length > 0) { + queue->length--; + } + } + osi_mutex_unlock(&queue->lock); + + return item; +} + +bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item) +{ + if (queue == NULL || item == NULL) { + return false; + } + + struct pkt_queue_header *header; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + header = &queue->header; + STAILQ_INSERT_TAIL(header, item, next); + queue->length++; + osi_mutex_unlock(&queue->lock); + + return true; +} + +size_t pkt_queue_length(const struct pkt_queue *queue) +{ + if (queue == NULL) { + return 0; + } + return queue->length; +} + +bool pkt_queue_is_empty(const struct pkt_queue *queue) +{ + return pkt_queue_length(queue) == 0; +} + +pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue) +{ + if (queue == NULL) { + return NULL; + } + + struct pkt_queue_header *header = &queue->header; + pkt_linked_item_t *item; + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + item = STAILQ_FIRST(header); + osi_mutex_unlock(&queue->lock); + + return item; +} From fb01677372a9eaad090abd47d3b867bda19baac3 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Wed, 20 Jul 2022 11:18:33 +0800 Subject: [PATCH 05/17] component/bt: add new OSI utility "fixed_pkt_queue", which has same functionality with "fixed_queue" --- components/bt/CMakeLists.txt | 1 + components/bt/common/osi/fixed_pkt_queue.c | 161 ++++++++++++++++++ .../common/osi/include/osi/fixed_pkt_queue.h | 79 +++++++++ 3 files changed, 241 insertions(+) create mode 100644 components/bt/common/osi/fixed_pkt_queue.c create mode 100644 components/bt/common/osi/include/osi/fixed_pkt_queue.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 6f23052610..9bb004a36d 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -37,6 +37,7 @@ if(CONFIG_BT_ENABLED) "common/osi/config.c" "common/osi/fixed_queue.c" "common/osi/pkt_queue.c" + "common/osi/fixed_pkt_queue.c" "common/osi/future.c" "common/osi/hash_functions.c" "common/osi/hash_map.c" diff --git a/components/bt/common/osi/fixed_pkt_queue.c b/components/bt/common/osi/fixed_pkt_queue.c new file mode 100644 index 0000000000..e98d454859 --- /dev/null +++ b/components/bt/common/osi/fixed_pkt_queue.c @@ -0,0 +1,161 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "osi/allocator.h" +#include "osi/pkt_queue.h" +#include "osi/fixed_pkt_queue.h" +#include "osi/osi.h" +#include "osi/semaphore.h" + +typedef struct fixed_pkt_queue_t { + struct pkt_queue *pkt_list; + osi_sem_t enqueue_sem; + osi_sem_t dequeue_sem; + size_t capacity; + fixed_pkt_queue_cb dequeue_ready; +} fixed_pkt_queue_t; + +fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity) +{ + fixed_pkt_queue_t *ret = osi_calloc(sizeof(fixed_pkt_queue_t)); + if (!ret) { + goto error; + } + + ret->capacity = capacity; + ret->pkt_list = pkt_queue_create(); + if (!ret->pkt_list) { + goto error; + } + + osi_sem_new(&ret->enqueue_sem, capacity, capacity); + if (!ret->enqueue_sem) { + goto error; + } + + osi_sem_new(&ret->dequeue_sem, capacity, 0); + if (!ret->dequeue_sem) { + goto error; + } + + return ret; + +error: + fixed_pkt_queue_free(ret, NULL); + return NULL; +} + +void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb) +{ + if (queue == NULL) { + return; + } + + fixed_pkt_queue_unregister_dequeue(queue); + + pkt_queue_destroy(queue->pkt_list, (pkt_queue_free_cb)free_cb); + queue->pkt_list = NULL; + + if (queue->enqueue_sem) { + osi_sem_free(&queue->enqueue_sem); + } + if (queue->dequeue_sem) { + osi_sem_free(&queue->dequeue_sem); + } + osi_free(queue); +} + +bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return true; + } + + return pkt_queue_is_empty(queue->pkt_list); +} + +size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return 0; + } + return pkt_queue_length(queue->pkt_list); +} + +size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + return queue->capacity; +} + +bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout) +{ + bool ret = false; + + assert(queue != NULL); + assert(linked_pkt != NULL); + + if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) { + return false; + } + + ret = pkt_queue_enqueue(queue->pkt_list, linked_pkt); + + assert(ret == true); + osi_sem_give(&queue->dequeue_sem); + + return ret; +} + +pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout) +{ + pkt_linked_item_t *ret = NULL; + + assert(queue != NULL); + + if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) { + return NULL; + } + ret = pkt_queue_dequeue(queue->pkt_list); + + osi_sem_give(&queue->enqueue_sem); + + return ret; +} + +pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue) +{ + if (queue == NULL) { + return NULL; + } + + return pkt_queue_try_peek_first(queue->pkt_list); +} + +void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb) +{ + assert(queue != NULL); + assert(ready_cb != NULL); + + queue->dequeue_ready = ready_cb; +} + +void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + queue->dequeue_ready = NULL; +} + +void fixed_pkt_queue_process(fixed_pkt_queue_t *queue) +{ + assert(queue != NULL); + + if (queue->dequeue_ready) { + queue->dequeue_ready(queue); + } +} diff --git a/components/bt/common/osi/include/osi/fixed_pkt_queue.h b/components/bt/common/osi/include/osi/fixed_pkt_queue.h new file mode 100644 index 0000000000..f4235ca5d9 --- /dev/null +++ b/components/bt/common/osi/include/osi/fixed_pkt_queue.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _FIXED_PKT_QUEUE_H_ +#define _FIXED_PKT_QUEUE_H_ + + +#include "osi/pkt_queue.h" +#include "osi/semaphore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FIXED_PKT_QUEUE_SIZE_MAX +#define FIXED_PKT_QUEUE_SIZE_MAX 254 +#endif + +#define FIXED_PKT_QUEUE_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT + +struct fixed_pkt_queue_t; + +typedef struct fixed_pkt_queue_t fixed_pkt_queue_t; + +typedef void (*fixed_pkt_queue_free_cb)(pkt_linked_item_t *data); +typedef void (*fixed_pkt_queue_cb)(fixed_pkt_queue_t *queue); + +// Creates a new fixed queue with the given |capacity|. If more elements than +// |capacity| are added to the queue, the caller is blocked until space is +// made available in the queue. Returns NULL on failure. The caller must free +// the returned queue with |fixed_pkt_queue_free|. +fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity); + +// Freeing a queue that is currently in use (i.e. has waiters +// blocked on it) results in undefined behaviour. +void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb); + +// Returns a value indicating whether the given |queue| is empty. If |queue| +// is NULL, the return value is true. +bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue); + +// Returns the length of the |queue|. If |queue| is NULL, the return value +// is 0. +size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue); + +// Returns the maximum number of elements this queue may hold. |queue| may +// not be NULL. +size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue); + +// Enqueues the given |data| into the |queue|. The caller will be blocked or immediately return or wait for timeout according to the parameter timeout. +// If enqueue failed, it will return false, otherwise return true +bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout); + +// Dequeues the next element from |queue|. If the queue is currently empty, +// this function will block the caller until an item is enqueued or immediately return or wait for timeout according to the parameter timeout. +// If dequeue failed, it will return NULL, otherwise return a point. +pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout); + +// Returns the first element from |queue|, if present, without dequeuing it. +// This function will never block the caller. Returns NULL if there are no +// elements in the queue or |queue| is NULL. +pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue); + +// Registers |queue| with |reactor| for dequeue operations. When there is an element +// in the queue, ready_cb will be called. The |context| parameter is passed, untouched, +// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be NULL. +// |context| may be NULL. +void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb); + +// Unregisters the dequeue ready callback for |queue| from whichever reactor +// it is registered with, if any. This function is idempotent. +void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue); + +void fixed_pkt_queue_process(fixed_pkt_queue_t *queue); + +#endif From ed509a8d52b1981f5e1141a9afe33bc6e6971fe4 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Sun, 17 Jul 2022 16:51:49 +0800 Subject: [PATCH 06/17] component/bt: use the OSI utility "osi_event" to handle A2DP sink data Rx processing --- components/bt/common/btc/core/btc_task.c | 5 +++ .../bt/common/btc/include/btc/btc_task.h | 7 ++++ .../btc/profile/std/a2dp/btc_a2dp_sink.c | 38 +++++++++---------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 840c858d18..79fddaed74 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -452,3 +452,8 @@ int get_btc_work_queue_size(void) { return osi_thread_queue_wait_size(btc_thread, 0); } + +osi_thread_t *btc_get_current_thread(void) +{ + return btc_thread; +} diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index cc9382590a..18253e870f 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -124,4 +124,11 @@ void btc_deinit(void); bool btc_check_queue_is_congest(void); int get_btc_work_queue_size(void); +/** + * get the BTC thread handle + * @return NULL: fail + * others: pointer of osi_thread structure of BTC + */ +osi_thread_t *btc_get_current_thread(void); + #endif /* __BTC_TASK_H__ */ diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index 999796732a..f969bd60c3 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -24,7 +24,6 @@ #include "common/bt_defs.h" #include "osi/allocator.h" #include "osi/mutex.h" -#include "osi/semaphore.h" #include "osi/thread.h" #include "osi/fixed_queue.h" #include "stack/a2d_api.h" @@ -46,8 +45,6 @@ #if (BTC_AV_SINK_INCLUDED == TRUE) -extern osi_thread_t *btc_thread; - /***************************************************************************** ** Constants *****************************************************************************/ @@ -90,6 +87,8 @@ enum { #define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ (25) #define JITTER_BUFFER_WATER_LEVEL (5) +#define BTC_A2DP_SNK_DATA_QUEUE_IDX (1) + typedef struct { uint32_t sig; void *param; @@ -105,7 +104,7 @@ typedef struct { typedef struct { BOOLEAN rx_flush; /* discards any incoming data when true */ UINT8 channel_count; - osi_sem_t post_sem; + struct osi_event *data_ready_event; fixed_queue_t *RxSbcQ; UINT32 sample_rate; } tBTC_A2DP_SINK_CB; @@ -222,7 +221,7 @@ bool btc_a2dp_sink_startup(void) APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##"); - a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_thread; + a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_get_current_thread(); if (btc_a2dp_sink_ctrl(BTC_MEDIA_TASK_SINK_INIT, NULL) == false) { goto error_exit; @@ -302,11 +301,6 @@ void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av) return; } -static void btc_a2dp_sink_data_post(void) -{ - osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_MAX_TIMEOUT); -} - /******************************************************************************* ** ** Function btc_a2dp_sink_clear_track @@ -364,7 +358,6 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context) tBT_SBC_HDR *p_msg; int nb_of_msgs_to_process = 0; - osi_sem_give(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem); if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) { APPL_TRACE_DEBUG(" QUE EMPTY "); } else { @@ -388,6 +381,10 @@ static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context) nb_of_msgs_to_process--; } APPL_TRACE_DEBUG(" Process Frames - "); + + if (!fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) { + osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT); + } } } @@ -699,9 +696,7 @@ UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt) APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT); if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= JITTER_BUFFER_WATER_LEVEL) { - if (osi_sem_take(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 0) == 0) { - btc_a2dp_sink_data_post(); - } + osi_thread_post_event(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event, OSI_THREAD_MAX_TIMEOUT); } } else { /* let caller deal with a failed allocation */ @@ -737,9 +732,12 @@ static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context) memset(&a2dp_sink_local_param.btc_aa_snk_cb, 0, sizeof(a2dp_sink_local_param.btc_aa_snk_cb)); btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON; - if (!a2dp_sink_local_param.btc_aa_snk_cb.post_sem) { - osi_sem_new(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 1, 1); - } + + struct osi_event *data_event = osi_event_create(btc_a2dp_sink_data_ready, NULL); + assert (data_event != NULL); + osi_event_bind(data_event, a2dp_sink_local_param.btc_aa_snk_task_hdl, BTC_A2DP_SNK_DATA_QUEUE_IDX); + a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = data_event; + a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX); btc_a2dp_control_init(); @@ -757,10 +755,8 @@ static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context) a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = NULL; - if (a2dp_sink_local_param.btc_aa_snk_cb.post_sem) { - osi_sem_free(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem); - a2dp_sink_local_param.btc_aa_snk_cb.post_sem = NULL; - } + osi_event_delete(a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event); + a2dp_sink_local_param.btc_aa_snk_cb.data_ready_event = NULL; } #endif /* BTC_AV_SINK_INCLUDED */ From 622148d4910460848834708a4cbcb4d8114ec3fb Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Sun, 17 Jul 2022 17:32:34 +0800 Subject: [PATCH 07/17] component/bt: use the OSI utility "osi_event" to handle A2DP source data Tx processing --- .../btc/profile/std/a2dp/btc_a2dp_source.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index b35ac83fa5..7c24426bb2 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -42,8 +42,6 @@ #if BTC_AV_SRC_INCLUDED -extern osi_thread_t *btc_thread; - /***************************************************************************** ** Constants *****************************************************************************/ @@ -118,6 +116,8 @@ enum { #define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5) #define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (27) // 18 for 20ms tick +#define BTC_A2DP_SRC_DATA_QUEUE_IDX (1) + typedef struct { uint32_t sig; void *param; @@ -154,6 +154,7 @@ typedef struct { tBTC_AV_MEDIA_FEEDINGS media_feeding; SBC_ENC_PARAMS encoder; osi_alarm_t *media_alarm; + struct osi_event *poll_data; } tBTC_A2DP_SOURCE_CB; typedef struct { @@ -283,7 +284,7 @@ bool btc_a2dp_source_startup(void) APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##"); - a2dp_source_local_param.btc_aa_src_task_hdl = btc_thread; + a2dp_source_local_param.btc_aa_src_task_hdl = btc_get_current_thread(); if (btc_a2dp_source_ctrl(BTC_MEDIA_TASK_INIT, NULL) == false) { goto error_exit; @@ -1509,7 +1510,7 @@ static void btc_a2dp_source_aa_stop_tx(void) static void btc_a2dp_source_alarm_cb(UNUSED_ATTR void *context) { if (a2dp_source_local_param.btc_aa_src_task_hdl) { - osi_thread_post(a2dp_source_local_param.btc_aa_src_task_hdl, btc_a2dp_source_handle_timer, NULL, 1, OSI_THREAD_MAX_TIMEOUT); + osi_thread_post_event(a2dp_source_local_param.btc_aa_src_cb.poll_data, OSI_THREAD_MAX_TIMEOUT); } else { APPL_TRACE_DEBUG("[%s] A2DP ALREADY FREED", __func__); btc_a2dp_source_aa_stop_tx(); @@ -1564,6 +1565,11 @@ static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context) btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_ON; + struct osi_event *poll_data = osi_event_create(btc_a2dp_source_handle_timer, NULL); + assert(poll_data != NULL); + osi_event_bind(poll_data, a2dp_source_local_param.btc_aa_src_task_hdl, BTC_A2DP_SRC_DATA_QUEUE_IDX); + a2dp_source_local_param.btc_aa_src_cb.poll_data = poll_data; + a2dp_source_local_param.btc_aa_src_cb.TxAaQ = fixed_queue_new(QUEUE_SIZE_MAX); btc_a2dp_control_init(); @@ -1579,6 +1585,9 @@ static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context) fixed_queue_free(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, osi_free_func); a2dp_source_local_param.btc_aa_src_cb.TxAaQ = NULL; + + osi_event_delete(a2dp_source_local_param.btc_aa_src_cb.poll_data); + a2dp_source_local_param.btc_aa_src_cb.poll_data = NULL; } #endif /* BTC_AV_INCLUDED */ From 09a79cf90a493595190c182d4eeb89c425f08d41 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Sun, 17 Jul 2022 20:09:56 +0800 Subject: [PATCH 08/17] component/bt: use the OSI utility "osi_event" for hci_hal_h4 upstream data packets handling --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 102 ++++++++++-------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 09d3e8841d..204599d05e 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -36,6 +36,8 @@ #define HCI_BLE_EVENT 0x3e #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) #define PACKET_TYPE_TO_INDEX(type) ((type) - 1) +#define HCI_UPSTREAM_DATA_QUEUE_IDX (1) + extern bool BTU_check_queue_is_congest(void); @@ -57,61 +59,66 @@ typedef struct { size_t buffer_size; fixed_queue_t *rx_q; uint16_t adv_free_num; + hci_hal_callbacks_t *callbacks; + osi_thread_t *hci_h4_thread; + struct osi_event *upstream_data_ready; } hci_hal_env_t; static hci_hal_env_t hci_hal_env; static const hci_hal_t interface; -static const hci_hal_callbacks_t *callbacks; static const esp_vhci_host_callback_t vhci_host_cb; -static osi_thread_t *hci_h4_thread; static void host_send_pkt_available_cb(void); static int host_recv_pkt_cb(uint8_t *data, uint16_t len); +static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet); +static void hci_upstream_data_handler(void *arg); +static bool hci_upstream_data_post(uint32_t timeout); -static void hci_hal_h4_rx_handler(void *arg); -static void event_uart_has_bytes(fixed_queue_t *queue); - - -static void hci_hal_env_init( - size_t buffer_size, - size_t max_buffer_count) +static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thread_t *task_thread) { - assert(buffer_size > 0); - assert(max_buffer_count > 0); + assert(upper_callbacks != NULL); + assert(task_thread != NULL); - hci_hal_env.buffer_size = buffer_size; + size_t max_buffer_count; +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + max_buffer_count = BLE_ADV_REPORT_FLOW_CONTROL_NUM + L2CAP_HOST_FC_ACL_BUFS + QUEUE_SIZE_MAX; // adv flow control num + ACL flow control num + hci cmd numeber +#else + max_buffer_count = QUEUE_SIZE_MAX; // adv flow control num + ACL flow control num + hci cmd numeber +#endif + + hci_hal_env.hci_h4_thread = task_thread; + hci_hal_env.callbacks = (hci_hal_callbacks_t *)upper_callbacks; + hci_hal_env.buffer_size = HCI_HAL_SERIAL_BUFFER_SIZE; hci_hal_env.adv_free_num = 0; hci_hal_env.rx_q = fixed_queue_new(max_buffer_count); - if (hci_hal_env.rx_q) { - fixed_queue_register_dequeue(hci_hal_env.rx_q, event_uart_has_bytes); - } else { - HCI_TRACE_ERROR("%s unable to create rx queue.\n", __func__); - } + assert(hci_hal_env.rx_q != NULL); - return; + struct osi_event *event = osi_event_create(hci_upstream_data_handler, NULL); + assert(event != NULL); + hci_hal_env.upstream_data_ready = event; + osi_event_bind(hci_hal_env.upstream_data_ready, hci_hal_env.hci_h4_thread, HCI_UPSTREAM_DATA_QUEUE_IDX); + + return true; } static void hci_hal_env_deinit(void) { fixed_queue_free(hci_hal_env.rx_q, osi_free_func); hci_hal_env.rx_q = NULL; + + osi_event_delete(hci_hal_env.upstream_data_ready); + hci_hal_env.upstream_data_ready = NULL; + + hci_hal_env.hci_h4_thread = NULL; + + memset(&hci_hal_env, 0, sizeof(hci_hal_env_t)); } static bool hal_open(const hci_hal_callbacks_t *upper_callbacks, void *task_thread) { - assert(upper_callbacks != NULL); - assert(task_thread != NULL); - - callbacks = upper_callbacks; -#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, BLE_ADV_REPORT_FLOW_CONTROL_NUM + L2CAP_HOST_FC_ACL_BUFS + QUEUE_SIZE_MAX); // adv flow control num + ACL flow control num + hci cmd numeber -#else - hci_hal_env_init(HCI_HAL_SERIAL_BUFFER_SIZE, QUEUE_SIZE_MAX); -#endif - - hci_h4_thread = (osi_thread_t *)task_thread; + hci_hal_env_init(upper_callbacks, (osi_thread_t *)task_thread); //register vhci host cb if (esp_vhci_host_register_callback(&vhci_host_cb) != ESP_OK) { @@ -124,8 +131,6 @@ static bool hal_open(const hci_hal_callbacks_t *upper_callbacks, void *task_thre static void hal_close(void) { hci_hal_env_deinit(); - - hci_h4_thread = NULL; } /** @@ -165,14 +170,27 @@ static uint16_t transmit_data(serial_data_type_t type, } // Internal functions -static void hci_hal_h4_rx_handler(void *arg) +static void hci_upstream_data_handler(void *arg) { - fixed_queue_process(hci_hal_env.rx_q); + fixed_queue_t *queue = hci_hal_env.rx_q; + BT_HDR *packet; + + size_t pkts_to_process = fixed_queue_length(queue); + for (size_t i = 0; i < pkts_to_process; i++) { + packet = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); + if (packet != NULL) { + hci_hal_h4_hdl_rx_packet(packet); + } + } + + if (!fixed_queue_is_empty(queue)) { + hci_upstream_data_post(OSI_THREAD_MAX_TIMEOUT); + } } -bool hci_hal_h4_task_post(uint32_t timeout) +static bool hci_upstream_data_post(uint32_t timeout) { - return osi_thread_post(hci_h4_thread, hci_hal_h4_rx_handler, NULL, 1, timeout); + return osi_thread_post_event(hci_hal_env.upstream_data_ready, timeout); } #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) @@ -294,16 +312,7 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) } #endif packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)]; - callbacks->packet_ready(packet); -} - -static void event_uart_has_bytes(fixed_queue_t *queue) -{ - BT_HDR *packet; - while (!fixed_queue_is_empty(queue)) { - packet = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); - hci_hal_h4_hdl_rx_packet(packet); - } + hci_hal_env.callbacks->packet_ready(packet); } static void host_send_pkt_available_cb(void) @@ -335,8 +344,7 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) pkt->layer_specific = 0; memcpy(pkt->data, data, len); fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); - hci_hal_h4_task_post(0); - + hci_upstream_data_post(OSI_THREAD_MAX_TIMEOUT); BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len); From f16e5df27fc492baf23d30baf073d49946a55e49 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Wed, 3 Aug 2022 21:54:52 +0800 Subject: [PATCH 09/17] component/bt: use the OSI utility "pkt_queue" to store ADV report packet in btu layer # Conflicts: # components/bt/host/bluedroid/hci/hci_hal_h4.c --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 153 +++++++++++++----- components/bt/host/bluedroid/hci/hci_layer.c | 17 +- .../host/bluedroid/hci/include/hci/hci_hal.h | 4 +- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 67 ++++++++ .../bluedroid/stack/btm/include/btm_ble_int.h | 7 + .../bt/host/bluedroid/stack/btu/btu_hcif.c | 20 +-- .../bt/host/bluedroid/stack/btu/btu_init.c | 5 + .../bt/host/bluedroid/stack/btu/btu_task.c | 12 ++ .../host/bluedroid/stack/include/stack/btu.h | 2 + 9 files changed, 228 insertions(+), 59 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 204599d05e..6f1f26bb4c 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -19,11 +19,11 @@ #include "common/bt_defs.h" #include "common/bt_trace.h" #include "stack/bt_types.h" -#include "osi/fixed_queue.h" #include "hci/hci_hal.h" #include "hci/hci_internals.h" #include "hci/hci_layer.h" #include "osi/thread.h" +#include "osi/pkt_queue.h" #include "esp_bt.h" #include "stack/hcimsgs.h" @@ -32,7 +32,6 @@ #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE #include "stack/hcimsgs.h" -#define HCI_HAL_SERIAL_BUFFER_SIZE 1026 #define HCI_BLE_EVENT 0x3e #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) #define PACKET_TYPE_TO_INDEX(type) ((type) - 1) @@ -56,8 +55,8 @@ static const uint16_t outbound_event_types[] = { }; typedef struct { - size_t buffer_size; fixed_queue_t *rx_q; + struct pkt_queue *adv_rpt_q; uint16_t adv_free_num; hci_hal_callbacks_t *callbacks; osi_thread_t *hci_h4_thread; @@ -72,6 +71,7 @@ static const esp_vhci_host_callback_t vhci_host_cb; static void host_send_pkt_available_cb(void); static int host_recv_pkt_cb(uint8_t *data, uint16_t len); static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet); +static void hci_hal_h4_hdl_rx_adv_rpt(pkt_linked_item_t *linked_pkt); static void hci_upstream_data_handler(void *arg); static bool hci_upstream_data_post(uint32_t timeout); @@ -80,21 +80,16 @@ static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thr assert(upper_callbacks != NULL); assert(task_thread != NULL); - size_t max_buffer_count; -#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - max_buffer_count = BLE_ADV_REPORT_FLOW_CONTROL_NUM + L2CAP_HOST_FC_ACL_BUFS + QUEUE_SIZE_MAX; // adv flow control num + ACL flow control num + hci cmd numeber -#else - max_buffer_count = QUEUE_SIZE_MAX; // adv flow control num + ACL flow control num + hci cmd numeber -#endif - hci_hal_env.hci_h4_thread = task_thread; hci_hal_env.callbacks = (hci_hal_callbacks_t *)upper_callbacks; - hci_hal_env.buffer_size = HCI_HAL_SERIAL_BUFFER_SIZE; hci_hal_env.adv_free_num = 0; - hci_hal_env.rx_q = fixed_queue_new(max_buffer_count); + hci_hal_env.rx_q = fixed_queue_new(QUEUE_SIZE_MAX); assert(hci_hal_env.rx_q != NULL); + hci_hal_env.adv_rpt_q = pkt_queue_create(); + assert(hci_hal_env.adv_rpt_q != NULL); + struct osi_event *event = osi_event_create(hci_upstream_data_handler, NULL); assert(event != NULL); hci_hal_env.upstream_data_ready = event; @@ -108,6 +103,9 @@ static void hci_hal_env_deinit(void) fixed_queue_free(hci_hal_env.rx_q, osi_free_func); hci_hal_env.rx_q = NULL; + pkt_queue_destroy(hci_hal_env.adv_rpt_q, NULL); + hci_hal_env.adv_rpt_q = NULL; + osi_event_delete(hci_hal_env.upstream_data_ready); hci_hal_env.upstream_data_ready = NULL; @@ -172,18 +170,31 @@ static uint16_t transmit_data(serial_data_type_t type, // Internal functions static void hci_upstream_data_handler(void *arg) { - fixed_queue_t *queue = hci_hal_env.rx_q; - BT_HDR *packet; + fixed_queue_t *rx_q = hci_hal_env.rx_q; + struct pkt_queue *adv_rpt_q = hci_hal_env.adv_rpt_q; + size_t pkts_to_process; - size_t pkts_to_process = fixed_queue_length(queue); - for (size_t i = 0; i < pkts_to_process; i++) { - packet = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); - if (packet != NULL) { - hci_hal_h4_hdl_rx_packet(packet); + do { + pkts_to_process = fixed_queue_length(rx_q); + for (size_t i = 0; i < pkts_to_process; i++) { + BT_HDR *packet = fixed_queue_dequeue(rx_q, 0); + if (packet != NULL) { + hci_hal_h4_hdl_rx_packet(packet); + } } - } + } while (0); - if (!fixed_queue_is_empty(queue)) { + do { + pkts_to_process = pkt_queue_length(adv_rpt_q); + for (size_t i = 0; i < pkts_to_process; i++) { + pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(adv_rpt_q); + if (linked_pkt != NULL) { + hci_hal_h4_hdl_rx_adv_rpt(linked_pkt); + } + } + } while (0); + + if (!fixed_queue_is_empty(rx_q) || pkt_queue_length(adv_rpt_q) > 0) { hci_upstream_data_post(OSI_THREAD_MAX_TIMEOUT); } } @@ -209,13 +220,13 @@ static void hci_packet_complete(BT_HDR *packet){ } #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE -bool host_recv_adv_packet(BT_HDR *packet) +bool host_recv_adv_packet(uint8_t *packet) { assert(packet); - if(packet->data[0] == DATA_TYPE_EVENT && packet->data[1] == HCI_BLE_EVENT) { - if(packet->data[3] == HCI_BLE_ADV_PKT_RPT_EVT + if(packet[0] == DATA_TYPE_EVENT && packet[1] == HCI_BLE_EVENT) { + if(packet[3] == HCI_BLE_ADV_PKT_RPT_EVT #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - || packet->data[3] == HCI_BLE_ADV_DISCARD_REPORT_EVT + || packet[3] == HCI_BLE_ADV_DISCARD_REPORT_EVT #endif ) { return true; @@ -228,7 +239,8 @@ bool host_recv_adv_packet(BT_HDR *packet) static void hci_update_adv_report_flow_control(BT_HDR *packet) { // this is adv packet - if(host_recv_adv_packet(packet)) { + uint8_t *data = packet->data + packet->offset; + if(host_recv_adv_packet(data)) { // update adv free number hci_hal_env.adv_free_num ++; if (esp_vhci_host_check_send_available()){ @@ -300,19 +312,61 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) return; } + packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)]; + hci_hal_env.callbacks->packet_ready(packet); +} + +static void hci_hal_h4_hdl_rx_adv_rpt(pkt_linked_item_t *linked_pkt) +{ + uint8_t type; + uint8_t hdr_size; + uint16_t length; + uint8_t *stream = NULL; + + if (!linked_pkt) { + return; + } + + BT_HDR* packet = (BT_HDR *)linked_pkt->data; + stream = packet->data + packet->offset; + + assert(host_recv_adv_packet(stream) == true); + + STREAM_TO_UINT8(type, stream); + packet->offset++; + packet->len--; + hdr_size = preamble_sizes[type - 1]; + + if (packet->len < hdr_size) { + HCI_TRACE_ERROR("Wrong packet length type=%d pkt_len=%d hdr_len=%d", + type, packet->len, hdr_size); + osi_free(linked_pkt); + return; + } + + stream += hdr_size - 1; + STREAM_TO_UINT8(length, stream); + if ((length + hdr_size) != packet->len) { + HCI_TRACE_ERROR("Wrong packet length type=%d hdr_len=%d pd_len=%d " + "pkt_len=%d", type, hdr_size, length, packet->len); + osi_free(linked_pkt); + return; + } + #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) hci_update_adv_report_flow_control(packet); #endif #if SCAN_QUEUE_CONGEST_CHECK - if(BTU_check_queue_is_congest() && host_recv_adv_packet(packet)) { + if(BTU_check_queue_is_congest()) { HCI_TRACE_DEBUG("BtuQueue is congested"); - osi_free(packet); + osi_free(linked_pkt); return; } #endif + packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)]; - hci_hal_env.callbacks->packet_ready(packet); + hci_hal_env.callbacks->adv_rpt_ready(linked_pkt); } static void host_send_pkt_available_cb(void) @@ -325,25 +379,44 @@ static void host_send_pkt_available_cb(void) static int host_recv_pkt_cb(uint8_t *data, uint16_t len) { //Target has packet to host, malloc new buffer for packet - BT_HDR *pkt; + BT_HDR *pkt = NULL; + pkt_linked_item_t *linked_pkt = NULL; size_t pkt_size; if (hci_hal_env.rx_q == NULL) { return 0; } - pkt_size = BT_HDR_SIZE + len; - pkt = (BT_HDR *) osi_calloc(pkt_size); + bool is_adv_rpt = host_recv_adv_packet(data); - if (!pkt) { - HCI_TRACE_ERROR("%s couldn't aquire memory for inbound data buffer.\n", __func__); - return -1; + if (!is_adv_rpt) { + pkt_size = BT_HDR_SIZE + len; + pkt = (BT_HDR *) osi_calloc(pkt_size); + if (!pkt) { + HCI_TRACE_ERROR("%s couldn't aquire memory for inbound data buffer.\n", __func__); + assert(0); + } + + pkt->offset = 0; + pkt->len = len; + pkt->layer_specific = 0; + memcpy(pkt->data, data, len); + fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); + } else { + pkt_size = BT_PKT_LINKED_HDR_SIZE + BT_HDR_SIZE + len; + linked_pkt = (pkt_linked_item_t *) osi_calloc(pkt_size); + if (!linked_pkt) { + // TODO: handle the adv report flow control exception + return 0; + } + pkt = (BT_HDR *)linked_pkt->data; + pkt->offset = 0; + pkt->len = len; + pkt->layer_specific = 0; + memcpy(pkt->data, data, len); + pkt_queue_enqueue(hci_hal_env.adv_rpt_q, linked_pkt); } - pkt->offset = 0; - pkt->len = len; - pkt->layer_specific = 0; - memcpy(pkt->data, data, len); - fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); + hci_upstream_data_post(OSI_THREAD_MAX_TIMEOUT); BTTRC_DUMP_BUFFER("Recv Pkt", pkt->data, len); diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index bd1ade792b..865dd3fd1a 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -102,6 +102,7 @@ static bool filter_incoming_event(BT_HDR *packet); static serial_data_type_t event_to_data_type(uint16_t event); static waiting_command_t *get_waiting_command(command_opcode_t opcode); static void dispatch_reassembled(BT_HDR *packet); +static void dispatch_adv_report(pkt_linked_item_t *linked_pkt); // Module lifecycle functions int hci_start_up(void) @@ -421,6 +422,11 @@ static void hal_says_packet_ready(BT_HDR *packet) } } +static void hal_says_adv_rpt_ready(pkt_linked_item_t *linked_pkt) +{ + dispatch_adv_report(linked_pkt); +} + // Returns true if the event was intercepted and should not proceed to // higher layers. Also inspects an incoming event for interesting // information, like how many commands are now able to be sent. @@ -518,6 +524,14 @@ static void dispatch_reassembled(BT_HDR *packet) } } +static void dispatch_adv_report(pkt_linked_item_t *linked_pkt) +{ + // Events should already have been dispatched before this point + //Tell Up-layer received packet. + if (btu_task_post(SIG_BTU_HCI_ADV_RPT_MSG, linked_pkt, OSI_THREAD_MAX_TIMEOUT) == false) { + osi_free(linked_pkt); + } +} // Misc internal functions // TODO(zachoverflow): we seem to do this a couple places, like the HCI inject module. #centralize @@ -570,7 +584,8 @@ static void init_layer_interface(void) } static const hci_hal_callbacks_t hal_callbacks = { - hal_says_packet_ready + hal_says_packet_ready, + hal_says_adv_rpt_ready, }; static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_hal.h b/components/bt/host/bluedroid/hci/include/hci/hci_hal.h index daf3dfb81a..5e16d69eb2 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_hal.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_hal.h @@ -21,7 +21,7 @@ #include #include - +#include "osi/pkt_queue.h" #include "stack/bt_types.h" typedef enum { @@ -32,12 +32,14 @@ typedef enum { } serial_data_type_t; typedef void (*packet_ready_cb)(BT_HDR *packet); +typedef void (*adv_rpt_ready_cb)(pkt_linked_item_t *linked_pkt); typedef struct { // Called when the HAL detects inbound data. // Data |type| may be ACL, SCO, or EVENT. // Executes in the context of the thread supplied to |init|. packet_ready_cb packet_ready; + adv_rpt_ready_cb adv_rpt_ready; /* // Called when the HAL detects inbound astronauts named Dave. diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 4ef3a960ff..8a8fd81471 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -82,6 +82,7 @@ static UINT8 btm_set_conn_mode_adv_init_addr(tBTM_BLE_INQ_CB *p_cb, tBLE_ADDR_TYPE *p_own_addr_type); static void btm_ble_stop_observe(void); static void btm_ble_stop_discover(void); +static void btm_adv_pkt_handler(void *arg); uint32_t BTM_BleUpdateOwnType(uint8_t *own_bda_type, tBTM_START_ADV_CMPL_CBACK *cb); #define BTM_BLE_INQ_RESULT 0x01 @@ -3455,6 +3456,41 @@ void btm_send_sel_conn_callback(BD_ADDR remote_bda, UINT8 evt_type, UINT8 *p_dat } } +static void btm_adv_pkt_handler(void *arg) +{ + UINT8 hci_evt_code, hci_evt_len; + UINT8 ble_sub_code; + + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + size_t pkts_to_process = pkt_queue_length(p_cb->adv_rpt_queue); + + for (size_t i = 0; i < pkts_to_process; i++) { + pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(p_cb->adv_rpt_queue); + assert(linked_pkt != NULL); + BT_HDR *packet = (BT_HDR *)linked_pkt->data; + uint8_t *p = packet->data + packet->offset; + STREAM_TO_UINT8 (hci_evt_code, p); + STREAM_TO_UINT8 (hci_evt_len, p); + STREAM_TO_UINT8 (ble_sub_code, p); + if (ble_sub_code == HCI_BLE_ADV_PKT_RPT_EVT) { + btm_ble_process_adv_pkt(p); + } else if (ble_sub_code == HCI_BLE_ADV_DISCARD_REPORT_EVT) { + btm_ble_process_adv_discard_evt(p); + } else { + assert (0); + } + + osi_free(linked_pkt); + } + + if (pkt_queue_length(p_cb->adv_rpt_queue) != 0) { + btu_task_post(SIG_BTU_HCI_ADV_RPT_MSG, NULL, OSI_THREAD_MAX_TIMEOUT); + } + + UNUSED(hci_evt_code); + UNUSED(hci_evt_len); +} + /******************************************************************************* ** ** Function btm_ble_process_adv_pkt @@ -4414,6 +4450,13 @@ void btm_ble_init (void) p_cb->inq_var.evt_type = BTM_BLE_NON_CONNECT_EVT; + p_cb->adv_rpt_queue = pkt_queue_create(); + assert(p_cb->adv_rpt_queue != NULL); + + p_cb->adv_rpt_ready = osi_event_create(btm_adv_pkt_handler, NULL); + assert(p_cb->adv_rpt_ready != NULL); + osi_event_bind(p_cb->adv_rpt_ready, btu_get_current_thread(), 0); + #if BLE_VND_INCLUDED == FALSE btm_ble_adv_filter_init(); #endif @@ -4436,6 +4479,12 @@ void btm_ble_free (void) fixed_queue_free(p_cb->conn_pending_q, osi_free_func); + pkt_queue_destroy(p_cb->adv_rpt_queue, NULL); + p_cb->adv_rpt_queue = NULL; + + osi_event_delete(p_cb->adv_rpt_ready); + p_cb->adv_rpt_ready = NULL; + #if BTM_DYNAMIC_MEMORY == TRUE osi_free(cmn_ble_gap_vsc_cb_ptr); cmn_ble_gap_vsc_cb_ptr = NULL; @@ -4530,4 +4579,22 @@ BOOLEAN BTM_Ble_Authorization(BD_ADDR bd_addr, BOOLEAN authorize) return FALSE; } +bool btm_ble_adv_pkt_ready(void) +{ + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + osi_thread_post_event(p_cb->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT); + + return true; +} + +bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt) +{ + if (pkt == NULL) { + return false; + } + + tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; + pkt_queue_enqueue(p_cb->adv_rpt_queue, pkt); + return true; +} #endif /* BLE_INCLUDED */ diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h index 017eb89223..125f513d4e 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h @@ -28,6 +28,8 @@ #include "common/bt_target.h" #include "osi/fixed_queue.h" +#include "osi/pkt_queue.h" +#include "osi/thread.h" #include "stack/hcidefs.h" #include "stack/btm_ble_api.h" #include "btm_int.h" @@ -341,6 +343,9 @@ typedef struct { tBTM_CMPL_CB *p_scan_cmpl_cb; TIMER_LIST_ENT scan_timer_ent; + struct pkt_queue *adv_rpt_queue; + struct osi_event *adv_rpt_ready; + /* background connection procedure cb value */ tBTM_BLE_CONN_TYPE bg_conn_type; UINT32 scan_int; @@ -384,6 +389,8 @@ extern "C" { void btm_ble_timeout(TIMER_LIST_ENT *p_tle); void btm_ble_process_adv_pkt (UINT8 *p); void btm_ble_process_adv_discard_evt(UINT8 *p); +bool btm_ble_adv_pkt_ready(void); +bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt); void btm_ble_proc_scan_rsp_rpt (UINT8 *p); tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb); BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 07c474be8b..d9130bd254 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -124,8 +124,6 @@ static void btu_hcif_ssr_evt_dump (UINT8 *p, UINT16 evt_len); #if BLE_INCLUDED == TRUE static void btu_ble_ll_conn_complete_evt (UINT8 *p, UINT16 evt_len); -static void btu_ble_process_adv_pkt (UINT8 *p); -static void btu_ble_process_adv_dis(UINT8 *p); static void btu_ble_read_remote_feat_evt (UINT8 *p); static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len); static void btu_ble_ll_get_conn_param_format_err_from_contoller (UINT8 status, UINT16 handle); @@ -360,10 +358,10 @@ void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg) switch (ble_sub_code) { case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */ - btu_ble_process_adv_pkt(p); - break; case HCI_BLE_ADV_DISCARD_REPORT_EVT: - btu_ble_process_adv_dis(p); + case HCI_BLE_DIRECT_ADV_EVT: + // These three events are directed to another specialized processing path + HCI_TRACE_ERROR("Unexpected HCI BLE event = 0x%02x", ble_sub_code); break; case HCI_BLE_CONN_COMPLETE_EVT: btu_ble_ll_conn_complete_evt(p, hci_evt_len); @@ -2015,18 +2013,6 @@ static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p) } #endif ///SMP_INCLUDED == TRUE -static void btu_ble_process_adv_pkt (UINT8 *p) -{ - HCI_TRACE_DEBUG("btu_ble_process_adv_pkt\n"); - - btm_ble_process_adv_pkt(p); -} - -static void btu_ble_process_adv_dis(UINT8 *p) -{ - btm_ble_process_adv_discard_evt(p); -} - static void btu_ble_ll_conn_complete_evt ( UINT8 *p, UINT16 evt_len) { btm_ble_conn_complete(p, evt_len, FALSE); diff --git a/components/bt/host/bluedroid/stack/btu/btu_init.c b/components/bt/host/bluedroid/stack/btu/btu_init.c index 7699a471f0..aff092dc35 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_init.c +++ b/components/bt/host/bluedroid/stack/btu/btu_init.c @@ -269,3 +269,8 @@ int get_btu_work_queue_size(void) { return osi_thread_queue_wait_size(btu_thread, 0); } + +osi_thread_t *btu_get_current_thread(void) +{ + return btu_thread; +} diff --git a/components/bt/host/bluedroid/stack/btu/btu_task.c b/components/bt/host/bluedroid/stack/btu/btu_task.c index e60fcfa43b..b4feded721 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_task.c +++ b/components/bt/host/bluedroid/stack/btu/btu_task.c @@ -227,6 +227,18 @@ bool btu_task_post(uint32_t sig, void *param, uint32_t timeout) case SIG_BTU_HCI_MSG: status = osi_thread_post(btu_thread, btu_hci_msg_process, param, 0, timeout); break; + case SIG_BTU_HCI_ADV_RPT_MSG: +#if BLE_INCLUDED == TRUE + if (param != NULL) { + btm_ble_adv_pkt_post(param); + } + btm_ble_adv_pkt_ready(); + status = true; +#else + osi_free(param); + status = false; +#endif + break; #if (defined(BTA_INCLUDED) && BTA_INCLUDED == TRUE) case SIG_BTU_BTA_MSG: status = osi_thread_post(btu_thread, bta_sys_event, param, 0, timeout); diff --git a/components/bt/host/bluedroid/stack/include/stack/btu.h b/components/bt/host/bluedroid/stack/include/stack/btu.h index b3b0bc3a43..836280c5ff 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btu.h +++ b/components/bt/host/bluedroid/stack/include/stack/btu.h @@ -176,6 +176,7 @@ typedef enum { SIG_BTU_GENERAL_ALARM, SIG_BTU_ONESHOT_ALARM, SIG_BTU_L2CAP_ALARM, + SIG_BTU_HCI_ADV_RPT_MSG, SIG_BTU_NUM, } SIG_BTU_t; @@ -298,6 +299,7 @@ bool btu_task_post(uint32_t sig, void *param, uint32_t timeout); int get_btu_work_queue_size(void); +osi_thread_t *btu_get_current_thread(void); /* #ifdef __cplusplus } From e406be3cf4845bae566b6533a53f5e530d974b6c Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 18 Jul 2022 12:56:52 +0800 Subject: [PATCH 10/17] component/bt: use the OSI utility "osi_event" to handle adv report in btc_layer --- components/bt/common/btc/core/btc_task.c | 9 +- .../bt/host/bluedroid/btc/core/btc_main.c | 3 - .../btc/profile/std/gap/btc_gap_ble.c | 129 ++++++++++++++---- .../btc/profile/std/include/btc_gap_ble.h | 1 + 4 files changed, 112 insertions(+), 30 deletions(-) diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 79fddaed74..c8fc083e24 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -56,6 +56,10 @@ #endif /* #if CLASSIC_BT_INCLUDED */ #endif +#if (BLE_INCLUDED == TRUE) +#include "btc_gap_ble.h" +#endif + #if CONFIG_BLE_MESH #include "btc_ble_mesh_ble.h" #include "btc_ble_mesh_prov.h" @@ -416,6 +420,7 @@ bt_status_t btc_init(void) #if (BLE_INCLUDED == TRUE) btc_gap_callback_init(); + btc_gap_ble_init(); #endif ///BLE_INCLUDED == TRUE #if SCAN_QUEUE_CONGEST_CHECK @@ -433,7 +438,9 @@ void btc_deinit(void) osi_thread_free(btc_thread); btc_thread = NULL; - +#if (BLE_INCLUDED == TRUE) + btc_gap_ble_deinit(); +#endif ///BLE_INCLUDED == TRUE #if SCAN_QUEUE_CONGEST_CHECK btc_adv_list_deinit(); #endif diff --git a/components/bt/host/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c index 00d0e5ff98..683be92cb3 100644 --- a/components/bt/host/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/bluedroid/btc/core/btc_main.c @@ -82,9 +82,6 @@ static void btc_deinit_bluetooth(void) #if BTA_DYNAMIC_MEMORY xSemaphoreTake(deinit_semaphore, BTA_DISABLE_DELAY / portTICK_PERIOD_MS); #endif /* #if BTA_DYNAMIC_MEMORY */ -#if (BLE_INCLUDED == TRUE) - btc_gap_ble_deinit(); -#endif ///BLE_INCLUDED == TRUE bta_dm_sm_deinit(); #if (GATTC_INCLUDED) bta_gattc_deinit(); diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index ca1462d009..6b9d3e68e7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -21,6 +21,8 @@ #include "btc/btc_dm.h" #include "btc/btc_util.h" #include "osi/mutex.h" +#include "osi/thread.h" +#include "osi/pkt_queue.h" #include "esp_bt.h" #if (BLE_INCLUDED == TRUE) @@ -48,6 +50,17 @@ static uint16_t btc_adv_list_count = 0; #define BTC_ADV_LIST_MAX_COUNT 200 #endif +#define BTC_GAP_BLE_ADV_RPT_QUEUE_IDX (1) + +#if (BLE_42_FEATURE_SUPPORT == TRUE) +typedef struct { + struct pkt_queue *adv_rpt_queue; + struct osi_event *adv_rpt_ready; +} btc_gap_ble_env_t; + +static btc_gap_ble_env_t btc_gap_ble_env; +#endif + static inline void btc_gap_ble_cb_to_app(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { esp_gap_ble_cb_t btc_gap_ble_cb = (esp_gap_ble_cb_t)btc_profile_cb_get(BTC_PID_GAP_BLE); @@ -548,8 +561,74 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA } } +static void btc_gap_ble_adv_pkt_handler(void *arg) +{ + btc_gap_ble_env_t *p_env = &btc_gap_ble_env; + size_t pkts_to_process = pkt_queue_length(p_env->adv_rpt_queue); + + for (size_t i = 0; i < pkts_to_process; i++) { + pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(p_env->adv_rpt_queue); + if (linked_pkt != NULL) { + esp_ble_gap_cb_param_t *param = (esp_ble_gap_cb_param_t *)(linked_pkt->data); + btc_gap_ble_cb_to_app(ESP_GAP_BLE_SCAN_RESULT_EVT, param); + osi_free(linked_pkt); + } + } + + if (pkt_queue_length(p_env->adv_rpt_queue) != 0) { + osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT); + } +} + +static void btc_process_adv_rpt_pkt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) +{ +#if SCAN_QUEUE_CONGEST_CHECK + if(btc_check_queue_is_congest()) { + BTC_TRACE_DEBUG("BtcQueue is congested"); + if(btc_get_adv_list_length() > BTC_ADV_LIST_MAX_LENGTH || btc_adv_list_count > BTC_ADV_LIST_MAX_COUNT) { + btc_adv_list_refresh(); + btc_adv_list_count = 0; + } + if(btc_check_adv_list(p_data->inq_res.bd_addr, p_data->inq_res.ble_addr_type)) { + return; + } + } + btc_adv_list_count ++; +#endif + + pkt_linked_item_t *linked_pkt = osi_calloc(BT_PKT_LINKED_HDR_SIZE + sizeof(esp_ble_gap_cb_param_t)); + if (linked_pkt == NULL) { + return; + } + + struct ble_scan_result_evt_param *scan_rst = (struct ble_scan_result_evt_param *)linked_pkt->data; + + do { + scan_rst->search_evt = event; + bdcpy(scan_rst->bda, p_data->inq_res.bd_addr); + scan_rst->dev_type = p_data->inq_res.device_type; + scan_rst->rssi = p_data->inq_res.rssi; + scan_rst->ble_addr_type = p_data->inq_res.ble_addr_type; + scan_rst->ble_evt_type = p_data->inq_res.ble_evt_type; + scan_rst->flag = p_data->inq_res.flag; + scan_rst->num_resps = 1; + scan_rst->adv_data_len = p_data->inq_res.adv_data_len; + scan_rst->scan_rsp_len = p_data->inq_res.scan_rsp_len; + memcpy(scan_rst->ble_adv, p_data->inq_res.p_eir, sizeof(scan_rst->ble_adv)); + } while (0); + + btc_gap_ble_env_t *p_env = &btc_gap_ble_env; + pkt_queue_enqueue(p_env->adv_rpt_queue, linked_pkt); + osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT); +} + static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) { + if (event == BTA_DM_INQ_RES_EVT) { + btc_process_adv_rpt_pkt(event, p_data); + return; + } + esp_ble_gap_cb_param_t param; btc_msg_t msg = {0}; @@ -559,32 +638,8 @@ static void btc_search_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data param.scan_rst.search_evt = event; switch (event) { - case BTA_DM_INQ_RES_EVT: { -#if SCAN_QUEUE_CONGEST_CHECK - if(btc_check_queue_is_congest()) { - BTC_TRACE_DEBUG("BtcQueue is congested"); - if(btc_get_adv_list_length() > BTC_ADV_LIST_MAX_LENGTH || btc_adv_list_count > BTC_ADV_LIST_MAX_COUNT) { - btc_adv_list_refresh(); - btc_adv_list_count = 0; - } - if(btc_check_adv_list(p_data->inq_res.bd_addr, p_data->inq_res.ble_addr_type)) { - return; - } - } - btc_adv_list_count ++; -#endif - bdcpy(param.scan_rst.bda, p_data->inq_res.bd_addr); - param.scan_rst.dev_type = p_data->inq_res.device_type; - param.scan_rst.rssi = p_data->inq_res.rssi; - param.scan_rst.ble_addr_type = p_data->inq_res.ble_addr_type; - param.scan_rst.ble_evt_type = p_data->inq_res.ble_evt_type; - param.scan_rst.flag = p_data->inq_res.flag; - param.scan_rst.num_resps = 1; - param.scan_rst.adv_data_len = p_data->inq_res.adv_data_len; - param.scan_rst.scan_rsp_len = p_data->inq_res.scan_rsp_len; - memcpy(param.scan_rst.ble_adv, p_data->inq_res.p_eir, sizeof(param.scan_rst.ble_adv)); + case BTA_DM_INQ_RES_EVT: break; - } case BTA_DM_INQ_CMPL_EVT: { param.scan_rst.num_resps = p_data->inq_cmpl.num_resps; BTC_TRACE_DEBUG("%s BLE observe complete. Num Resp %d\n", __FUNCTION__, p_data->inq_cmpl.num_resps); @@ -1841,9 +1896,31 @@ void btc_gap_callback_init(void) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) } +bool btc_gap_ble_init(void) +{ +#if (BLE_42_FEATURE_SUPPORT == TRUE) + btc_gap_ble_env_t *p_env = &btc_gap_ble_env; + p_env->adv_rpt_queue = pkt_queue_create(); + assert(p_env->adv_rpt_queue != NULL); + + p_env->adv_rpt_ready = osi_event_create(btc_gap_ble_adv_pkt_handler, NULL); + assert(p_env->adv_rpt_ready != NULL); + osi_event_bind(p_env->adv_rpt_ready, btc_get_current_thread(), BTC_GAP_BLE_ADV_RPT_QUEUE_IDX); +#endif + return true; +} + void btc_gap_ble_deinit(void) { - #if (BLE_42_FEATURE_SUPPORT == TRUE) +#if (BLE_42_FEATURE_SUPPORT == TRUE) + btc_gap_ble_env_t *p_env = &btc_gap_ble_env; + + osi_event_delete(p_env->adv_rpt_ready); + p_env->adv_rpt_ready = NULL; + + pkt_queue_destroy(p_env->adv_rpt_queue, NULL); + p_env->adv_rpt_queue = NULL; + btc_cleanup_adv_data(&gl_bta_adv_data); btc_cleanup_adv_data(&gl_bta_scan_rsp_data); #endif // #if (BLE_42_FEATURE_SUPPORT == TRUE) diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h index 149a320bf9..37679d8dea 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -353,6 +353,7 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg); void btc_gap_ble_cb_deep_free(btc_msg_t *msg); void btc_gap_ble_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); void btc_gap_callback_init(void); +bool btc_gap_ble_init(void); void btc_gap_ble_deinit(void); void btc_adv_list_init(void); void btc_adv_list_deinit(void); From 64572b7ff2424d651fe7b95aedd738e0d70a1255 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 18 Jul 2022 15:53:08 +0800 Subject: [PATCH 11/17] component/bt: add simple ADV flow control mechanism -- drop the packets when the adv report queues are considered full --- .../host/bluedroid/btc/profile/std/gap/btc_gap_ble.c | 12 +++++++++++- components/bt/host/bluedroid/hci/hci_hal_h4.c | 7 +++++++ components/bt/host/bluedroid/stack/btm/btm_ble_gap.c | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 6b9d3e68e7..92cc51c55d 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -51,6 +51,8 @@ static uint16_t btc_adv_list_count = 0; #endif #define BTC_GAP_BLE_ADV_RPT_QUEUE_IDX (1) +#define BTC_GAP_BLE_ADV_RPT_BATCH_SIZE (10) +#define BTC_GAP_BLE_ADV_RPT_QUEUE_LEN_MAX (200) #if (BLE_42_FEATURE_SUPPORT == TRUE) typedef struct { @@ -565,6 +567,9 @@ static void btc_gap_ble_adv_pkt_handler(void *arg) { btc_gap_ble_env_t *p_env = &btc_gap_ble_env; size_t pkts_to_process = pkt_queue_length(p_env->adv_rpt_queue); + if (pkts_to_process > BTC_GAP_BLE_ADV_RPT_BATCH_SIZE) { + pkts_to_process = BTC_GAP_BLE_ADV_RPT_BATCH_SIZE; + } for (size_t i = 0; i < pkts_to_process; i++) { pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(p_env->adv_rpt_queue); @@ -596,6 +601,12 @@ static void btc_process_adv_rpt_pkt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_ btc_adv_list_count ++; #endif + // drop ADV packets if data queue length goes above threshold + btc_gap_ble_env_t *p_env = &btc_gap_ble_env; + if (pkt_queue_length(p_env->adv_rpt_queue) >= BTC_GAP_BLE_ADV_RPT_QUEUE_LEN_MAX) { + return; + } + pkt_linked_item_t *linked_pkt = osi_calloc(BT_PKT_LINKED_HDR_SIZE + sizeof(esp_ble_gap_cb_param_t)); if (linked_pkt == NULL) { return; @@ -617,7 +628,6 @@ static void btc_process_adv_rpt_pkt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_ memcpy(scan_rst->ble_adv, p_data->inq_res.p_eir, sizeof(scan_rst->ble_adv)); } while (0); - btc_gap_ble_env_t *p_env = &btc_gap_ble_env; pkt_queue_enqueue(p_env->adv_rpt_queue, linked_pkt); osi_thread_post_event(p_env->adv_rpt_ready, OSI_THREAD_MAX_TIMEOUT); } diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 6f1f26bb4c..53e37dc154 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -36,6 +36,7 @@ #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) #define PACKET_TYPE_TO_INDEX(type) ((type) - 1) #define HCI_UPSTREAM_DATA_QUEUE_IDX (1) +#define HCI_HAL_BLE_ADV_RPT_QUEUE_LEN_MAX (200) extern bool BTU_check_queue_is_congest(void); @@ -403,6 +404,12 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) memcpy(pkt->data, data, len); fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); } else { +#if !BLE_ADV_REPORT_FLOW_CONTROL + // drop the packets if pkt_queue length goes beyond upper limit + if (pkt_queue_length(hci_hal_env.adv_rpt_q) > HCI_HAL_BLE_ADV_RPT_QUEUE_LEN_MAX) { + return 0; + } +#endif pkt_size = BT_PKT_LINKED_HDR_SIZE + BT_HDR_SIZE + len; linked_pkt = (pkt_linked_item_t *) osi_calloc(pkt_size); if (!linked_pkt) { diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 8a8fd81471..dd25ec039f 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -57,6 +57,8 @@ #define MIN_ADV_LENGTH 2 #define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9 +#define BTM_BLE_GAP_ADV_RPT_BATCH_SIZE (10) + #if BTM_DYNAMIC_MEMORY == FALSE static tBTM_BLE_VSC_CB cmn_ble_gap_vsc_cb; #else @@ -3463,6 +3465,9 @@ static void btm_adv_pkt_handler(void *arg) tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; size_t pkts_to_process = pkt_queue_length(p_cb->adv_rpt_queue); + if (pkts_to_process > BTM_BLE_GAP_ADV_RPT_BATCH_SIZE) { + pkts_to_process = BTM_BLE_GAP_ADV_RPT_BATCH_SIZE; + } for (size_t i = 0; i < pkts_to_process; i++) { pkt_linked_item_t *linked_pkt = pkt_queue_dequeue(p_cb->adv_rpt_queue); From 2da8b2c78b1608cd49b7c6a3085b34a322b076d8 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Mon, 18 Jul 2022 19:40:34 +0800 Subject: [PATCH 12/17] component/bt: fix adv report flow control logic, give ADV report credits every 10 packets --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 125 ++++++++++++++---- components/bt/host/bluedroid/hci/hci_layer.c | 3 + .../bluedroid/hci/include/hci/hci_layer.h | 7 + .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 5 +- 4 files changed, 113 insertions(+), 27 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 53e37dc154..57f7e07dbd 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -24,6 +24,9 @@ #include "hci/hci_layer.h" #include "osi/thread.h" #include "osi/pkt_queue.h" +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +#include "osi/mutex.h" +#endif #include "esp_bt.h" #include "stack/hcimsgs.h" @@ -36,7 +39,11 @@ #define PACKET_TYPE_TO_INBOUND_INDEX(type) ((type) - 2) #define PACKET_TYPE_TO_INDEX(type) ((type) - 1) #define HCI_UPSTREAM_DATA_QUEUE_IDX (1) +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +#define HCI_BLE_ADV_MIN_CREDITS_TO_RELEASE (10) +#else #define HCI_HAL_BLE_ADV_RPT_QUEUE_LEN_MAX (200) +#endif extern bool BTU_check_queue_is_congest(void); @@ -58,7 +65,11 @@ static const uint16_t outbound_event_types[] = { typedef struct { fixed_queue_t *rx_q; struct pkt_queue *adv_rpt_q; - uint16_t adv_free_num; +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + osi_mutex_t adv_flow_lock; + int adv_credits; + int adv_credits_to_release; +#endif hci_hal_callbacks_t *callbacks; osi_thread_t *hci_h4_thread; struct osi_event *upstream_data_ready; @@ -83,7 +94,14 @@ static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thr hci_hal_env.hci_h4_thread = task_thread; hci_hal_env.callbacks = (hci_hal_callbacks_t *)upper_callbacks; - hci_hal_env.adv_free_num = 0; + +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + osi_mutex_new(&hci_hal_env.adv_flow_lock); + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + hci_hal_env.adv_credits = BLE_ADV_REPORT_FLOW_CONTROL_NUM; + hci_hal_env.adv_credits_to_release = 0; + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); +#endif hci_hal_env.rx_q = fixed_queue_new(QUEUE_SIZE_MAX); assert(hci_hal_env.rx_q != NULL); @@ -110,6 +128,10 @@ static void hci_hal_env_deinit(void) osi_event_delete(hci_hal_env.upstream_data_ready); hci_hal_env.upstream_data_ready = NULL; +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + osi_mutex_free(&hci_hal_env.adv_flow_lock); +#endif + hci_hal_env.hci_h4_thread = NULL; memset(&hci_hal_env, 0, sizeof(hci_hal_env_t)); @@ -237,22 +259,66 @@ bool host_recv_adv_packet(uint8_t *packet) } #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) -static void hci_update_adv_report_flow_control(BT_HDR *packet) +static void hci_adv_credits_consumed(uint16_t num) { - // this is adv packet - uint8_t *data = packet->data + packet->offset; - if(host_recv_adv_packet(data)) { - // update adv free number - hci_hal_env.adv_free_num ++; - if (esp_vhci_host_check_send_available()){ - // send hci cmd - btsnd_hcic_ble_update_adv_report_flow_control(hci_hal_env.adv_free_num); - hci_hal_env.adv_free_num = 0; - } else { - //do nothing - } + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + assert(hci_hal_env.adv_credits >= num); + hci_hal_env.adv_credits -= num; + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); +} + +int hci_adv_credits_prep_to_release(uint16_t num) +{ + if (num == 0) { + return hci_hal_env.adv_credits_to_release; } + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + int credits_to_release = hci_hal_env.adv_credits_to_release + num; + assert(hci_hal_env.adv_credits_to_release <= BLE_ADV_REPORT_FLOW_CONTROL_NUM); + hci_hal_env.adv_credits_to_release = credits_to_release; + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + + return credits_to_release; +} + +static int hci_adv_credits_release(void) +{ + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + int credits_released = hci_hal_env.adv_credits_to_release; + hci_hal_env.adv_credits += credits_released; + hci_hal_env.adv_credits_to_release -= credits_released; + assert(hci_hal_env.adv_credits <= BLE_ADV_REPORT_FLOW_CONTROL_NUM); + assert(hci_hal_env.adv_credits_to_release >= 0); + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + + return credits_released; +} + +int hci_adv_credits_try_release(uint16_t num) +{ + int credits_released = 0; + if (hci_adv_credits_prep_to_release(num) >= HCI_BLE_ADV_MIN_CREDITS_TO_RELEASE) { + credits_released = hci_adv_credits_release(); + assert(credits_released >= 0); + if (credits_released > 0) { + // TODO: handle the exception that the command is discarded due to heap exhaustion + btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + } + } + return credits_released; +} + +int hci_adv_credits_force_release(uint16_t num) +{ + hci_adv_credits_prep_to_release(num); + int credits_released = hci_adv_credits_release(); + if (credits_released > 0) { + // TODO: handle the exception that the command is discarded due to heap exhaustion + btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + } + + return credits_released; } #endif @@ -341,8 +407,7 @@ static void hci_hal_h4_hdl_rx_adv_rpt(pkt_linked_item_t *linked_pkt) if (packet->len < hdr_size) { HCI_TRACE_ERROR("Wrong packet length type=%d pkt_len=%d hdr_len=%d", type, packet->len, hdr_size); - osi_free(linked_pkt); - return; + goto _discard_packet; } stream += hdr_size - 1; @@ -350,24 +415,26 @@ static void hci_hal_h4_hdl_rx_adv_rpt(pkt_linked_item_t *linked_pkt) if ((length + hdr_size) != packet->len) { HCI_TRACE_ERROR("Wrong packet length type=%d hdr_len=%d pd_len=%d " "pkt_len=%d", type, hdr_size, length, packet->len); - osi_free(linked_pkt); - return; + goto _discard_packet; } -#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - hci_update_adv_report_flow_control(packet); -#endif - #if SCAN_QUEUE_CONGEST_CHECK if(BTU_check_queue_is_congest()) { HCI_TRACE_DEBUG("BtuQueue is congested"); - osi_free(linked_pkt); - return; + goto _discard_packet; } #endif packet->event = outbound_event_types[PACKET_TYPE_TO_INDEX(type)]; hci_hal_env.callbacks->adv_rpt_ready(linked_pkt); + + return; + +_discard_packet: + osi_free(linked_pkt); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_adv_credits_prep_to_release(1); +#endif } static void host_send_pkt_available_cb(void) @@ -413,7 +480,10 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) pkt_size = BT_PKT_LINKED_HDR_SIZE + BT_HDR_SIZE + len; linked_pkt = (pkt_linked_item_t *) osi_calloc(pkt_size); if (!linked_pkt) { - // TODO: handle the adv report flow control exception +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_adv_credits_consumed(1); + hci_adv_credits_prep_to_release(1); +#endif return 0; } pkt = (BT_HDR *)linked_pkt->data; @@ -422,6 +492,9 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) pkt->layer_specific = 0; memcpy(pkt->data, data, len); pkt_queue_enqueue(hci_hal_env.adv_rpt_q, linked_pkt); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_adv_credits_consumed(1); +#endif } hci_upstream_data_post(OSI_THREAD_MAX_TIMEOUT); diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 865dd3fd1a..0365c45f93 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -530,6 +530,9 @@ static void dispatch_adv_report(pkt_linked_item_t *linked_pkt) //Tell Up-layer received packet. if (btu_task_post(SIG_BTU_HCI_ADV_RPT_MSG, linked_pkt, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(linked_pkt); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_adv_credits_try_release(1); +#endif } } // Misc internal functions diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 6bfacdff5c..6ba4ccd18c 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -19,6 +19,7 @@ #ifndef _HCI_LAYER_H_ #define _HCI_LAYER_H_ +#include "common/bt_target.h" #include "stack/bt_types.h" #include "osi/allocator.h" #include "osi/osi.h" @@ -99,4 +100,10 @@ void hci_shut_down(void); bool hci_host_task_post(uint32_t timeout); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +int hci_adv_credits_prep_to_release(uint16_t num); +int hci_adv_credits_try_release(uint16_t num); +int hci_adv_credits_force_release(uint16_t num); +#endif + #endif /* _HCI_LAYER_H_ */ diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index dd25ec039f..f1a96a497d 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -34,7 +34,7 @@ #include "device/controller.h" #include "stack/hcimsgs.h" #include "stack/gap_api.h" - +#include "hci/hci_layer.h" #if BLE_INCLUDED == TRUE #include "l2c_int.h" @@ -3486,6 +3486,9 @@ static void btm_adv_pkt_handler(void *arg) } osi_free(linked_pkt); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_adv_credits_try_release(1); +#endif } if (pkt_queue_length(p_cb->adv_rpt_queue) != 0) { From dd02446224dba5bb04701cf703c2487edfabf830 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Tue, 19 Jul 2022 15:32:54 +0800 Subject: [PATCH 13/17] component/bt: add a timer to monitor the adv flow control credits downwards procedure --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 57f7e07dbd..77cde40d5a 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -26,6 +26,7 @@ #include "osi/pkt_queue.h" #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) #include "osi/mutex.h" +#include "osi/alarm.h" #endif #include "esp_bt.h" #include "stack/hcimsgs.h" @@ -41,6 +42,7 @@ #define HCI_UPSTREAM_DATA_QUEUE_IDX (1) #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) #define HCI_BLE_ADV_MIN_CREDITS_TO_RELEASE (10) +#define HCI_ADV_FLOW_MONITOR_PERIOD_MS (500) #else #define HCI_HAL_BLE_ADV_RPT_QUEUE_LEN_MAX (200) #endif @@ -67,6 +69,7 @@ typedef struct { struct pkt_queue *adv_rpt_q; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) osi_mutex_t adv_flow_lock; + osi_alarm_t *adv_flow_monitor; int adv_credits; int adv_credits_to_release; #endif @@ -87,6 +90,10 @@ static void hci_hal_h4_hdl_rx_adv_rpt(pkt_linked_item_t *linked_pkt); static void hci_upstream_data_handler(void *arg); static bool hci_upstream_data_post(uint32_t timeout); +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +static void hci_adv_flow_monitor(void *context); +#endif + static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thread_t *task_thread) { assert(upper_callbacks != NULL); @@ -101,6 +108,8 @@ static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thr hci_hal_env.adv_credits = BLE_ADV_REPORT_FLOW_CONTROL_NUM; hci_hal_env.adv_credits_to_release = 0; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + hci_hal_env.adv_flow_monitor = osi_alarm_new("adv_fc_mon", hci_adv_flow_monitor, NULL, HCI_ADV_FLOW_MONITOR_PERIOD_MS); + assert (hci_hal_env.adv_flow_monitor != NULL); #endif hci_hal_env.rx_q = fixed_queue_new(QUEUE_SIZE_MAX); @@ -129,6 +138,9 @@ static void hci_hal_env_deinit(void) hci_hal_env.upstream_data_ready = NULL; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + osi_alarm_cancel(hci_hal_env.adv_flow_monitor); + osi_alarm_free(hci_hal_env.adv_flow_monitor); + hci_hal_env.adv_flow_monitor = NULL; osi_mutex_free(&hci_hal_env.adv_flow_lock); #endif @@ -259,6 +271,11 @@ bool host_recv_adv_packet(uint8_t *packet) } #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) +static void hci_adv_flow_monitor(void *context) +{ + hci_adv_credits_force_release(0); +} + static void hci_adv_credits_consumed(uint16_t num) { osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); @@ -279,6 +296,10 @@ int hci_adv_credits_prep_to_release(uint16_t num) hci_hal_env.adv_credits_to_release = credits_to_release; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + if (credits_to_release == num) { + osi_alarm_cancel(hci_hal_env.adv_flow_monitor); + osi_alarm_set(hci_hal_env.adv_flow_monitor, HCI_ADV_FLOW_MONITOR_PERIOD_MS); + } return credits_to_release; } @@ -292,6 +313,9 @@ static int hci_adv_credits_release(void) assert(hci_hal_env.adv_credits_to_release >= 0); osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + if (hci_hal_env.adv_credits_to_release == 0) { + osi_alarm_cancel(hci_hal_env.adv_flow_monitor); + } return credits_released; } From 20705588b2bc36c134f42b4b10e97d5891d4adb7 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Tue, 19 Jul 2022 22:16:12 +0800 Subject: [PATCH 14/17] component/bt: use fixed_pkt_queue instead of fixed_queue for hci commands some fixes after modifications: 1. removed the use of waiting_command_t 2. fix assert for HCI write_eir command 3. fixed the crash upon handling command status event when trying to free to the HCI command buffer 4. fixed the issue in transmitting HCI vendor specific commands 5. fixed the lost command complete callbacks for HCI commands LE_RAND and LE_ENCRYPT --- components/bt/host/bluedroid/hci/hci_layer.c | 136 ++++++++---------- .../host/bluedroid/hci/hci_packet_factory.c | 16 +-- .../bluedroid/hci/include/hci/hci_layer.h | 2 + .../bt/host/bluedroid/stack/btm/btm_devctl.c | 5 +- .../bt/host/bluedroid/stack/btm/btm_inq.c | 1 + .../bt/host/bluedroid/stack/btu/btu_hcif.c | 49 +++++-- .../bt/host/bluedroid/stack/hcic/hciblecmds.c | 23 ++- .../bt/host/bluedroid/stack/hcic/hcicmds.c | 26 ++-- .../bluedroid/stack/include/stack/hcimsgs.h | 61 +++++++- 9 files changed, 187 insertions(+), 132 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 0365c45f93..8d79043dd4 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -35,6 +35,7 @@ #include "osi/thread.h" #include "osi/mutex.h" #include "osi/fixed_queue.h" +#include "osi/fixed_pkt_queue.h" #define HCI_HOST_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE) #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) @@ -44,15 +45,6 @@ #define HCI_HOST_TASK_WORKQUEUE0_LEN (0) #define HCI_HOST_TASK_WORKQUEUE1_LEN (5) -typedef struct { - uint16_t opcode; - future_t *complete_future; - command_complete_cb complete_callback; - command_status_cb status_callback; - void *context; - BT_HDR *command; -} waiting_command_t; - typedef struct { bool timer_is_set; osi_alarm_t *command_response_timer; @@ -62,7 +54,7 @@ typedef struct { typedef struct { int command_credits; - fixed_queue_t *command_queue; + fixed_pkt_queue_t *command_queue; fixed_queue_t *packet_queue; command_waiting_response_t cmd_waiting_q; @@ -93,14 +85,14 @@ static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks; static int hci_layer_init_env(void); static void hci_layer_deinit_env(void); static void hci_host_thread_handler(void *arg); -static void event_command_ready(fixed_queue_t *queue); +static void event_command_ready(fixed_pkt_queue_t *queue); static void event_packet_ready(fixed_queue_t *queue); static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q); static void command_timed_out(void *context); static void hal_says_packet_ready(BT_HDR *packet); static bool filter_incoming_event(BT_HDR *packet); static serial_data_type_t event_to_data_type(uint16_t event); -static waiting_command_t *get_waiting_command(command_opcode_t opcode); +static pkt_linked_item_t *get_waiting_command(command_opcode_t opcode); static void dispatch_reassembled(BT_HDR *packet); static void dispatch_adv_report(pkt_linked_item_t *linked_pkt); @@ -156,9 +148,9 @@ static int hci_layer_init_env(void) // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control) // This value can change when you get a command complete or command status event. hci_host_env.command_credits = 1; - hci_host_env.command_queue = fixed_queue_new(QUEUE_SIZE_MAX); + hci_host_env.command_queue = fixed_pkt_queue_new(QUEUE_SIZE_MAX); if (hci_host_env.command_queue) { - fixed_queue_register_dequeue(hci_host_env.command_queue, event_command_ready); + fixed_pkt_queue_register_dequeue(hci_host_env.command_queue, event_command_ready); } else { HCI_TRACE_ERROR("%s unable to create pending command queue.", __func__); return -1; @@ -198,7 +190,7 @@ static void hci_layer_deinit_env(void) command_waiting_response_t *cmd_wait_q; if (hci_host_env.command_queue) { - fixed_queue_free(hci_host_env.command_queue, osi_free_func); + fixed_pkt_queue_free(hci_host_env.command_queue, (fixed_pkt_queue_free_cb)osi_free_func); } if (hci_host_env.packet_queue) { fixed_queue_free(hci_host_env.packet_queue, osi_free_func); @@ -230,9 +222,9 @@ static void hci_host_thread_handler(void *arg) if (pkt != NULL) { packet_fragmenter->fragment_and_dispatch(pkt); } else { - if (!fixed_queue_is_empty(hci_host_env.command_queue) && + if (!fixed_pkt_queue_is_empty(hci_host_env.command_queue) && hci_host_env.command_credits > 0) { - fixed_queue_process(hci_host_env.command_queue); + fixed_pkt_queue_process(hci_host_env.command_queue); } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { fixed_queue_process(hci_host_env.packet_queue); } @@ -246,48 +238,38 @@ static void transmit_command( command_status_cb status_callback, void *context) { - uint8_t *stream; - waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); - if (!wait_entry) { - HCI_TRACE_ERROR("%s couldn't allocate space for wait entry.", __func__); - return; - } - - stream = command->data + command->offset; - STREAM_TO_UINT16(wait_entry->opcode, stream); - wait_entry->complete_callback = complete_callback; - wait_entry->status_callback = status_callback; - wait_entry->command = command; - wait_entry->context = context; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command); + pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); + assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; - HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); + HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", metadata->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); - fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); + fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT); hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } static future_t *transmit_command_futured(BT_HDR *command) { - waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); - assert(wait_entry != NULL); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(command); + pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); + + assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + metadata->flags_vnd |= HCI_CMD_MSG_F_VND_FUTURE; future_t *future = future_new(); - uint8_t *stream = command->data + command->offset; - STREAM_TO_UINT16(wait_entry->opcode, stream); - wait_entry->complete_future = future; - wait_entry->command = command; + metadata->complete_future = future; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; - fixed_queue_enqueue(hci_host_env.command_queue, wait_entry, FIXED_QUEUE_MAX_TIMEOUT); + fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT); hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); return future; } @@ -295,8 +277,8 @@ static future_t *transmit_command_futured(BT_HDR *command) static void transmit_downward(uint16_t type, void *data) { if (type == MSG_STACK_TO_HC_HCI_CMD) { - transmit_command((BT_HDR *)data, NULL, NULL, NULL); - HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__); + HCI_TRACE_ERROR("%s legacy transmit of command. Use transmit_command instead.\n", __func__); + assert(0); } else { fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT); } @@ -306,21 +288,18 @@ static void transmit_downward(uint16_t type, void *data) // Command/packet transmitting functions -static void event_command_ready(fixed_queue_t *queue) +static void event_command_ready(fixed_pkt_queue_t *queue) { - waiting_command_t *wait_entry = NULL; + pkt_linked_item_t *wait_entry = NULL; command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; - wait_entry = fixed_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); + wait_entry = fixed_pkt_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); - if(wait_entry->opcode == HCI_HOST_NUM_PACKETS_DONE -#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) - || wait_entry->opcode == HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL -#endif - ){ - packet_fragmenter->fragment_and_dispatch(wait_entry->command); - osi_free(wait_entry->command); - osi_free(wait_entry); + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + if (metadata->flags_src & HCI_CMD_MSG_F_SRC_NOACK) { + packet_fragmenter->fragment_and_dispatch(&metadata->command); + hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func; + free_func(wait_entry); return; } hci_host_env.command_credits--; @@ -330,7 +309,7 @@ static void event_command_ready(fixed_queue_t *queue) osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); // Send it off - packet_fragmenter->fragment_and_dispatch(wait_entry->command); + packet_fragmenter->fragment_and_dispatch(&metadata->command); restart_command_waiting_response_timer(cmd_wait_q); } @@ -395,7 +374,7 @@ static void restart_command_waiting_response_timer(command_waiting_response_t *c static void command_timed_out(void *context) { command_waiting_response_t *cmd_wait_q = (command_waiting_response_t *)context; - waiting_command_t *wait_entry; + pkt_linked_item_t *wait_entry; osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ? @@ -408,7 +387,8 @@ static void command_timed_out(void *context) // We shouldn't try to recover the stack from this command timeout. // If it's caused by a software bug, fix it. If it's a hardware bug, fix it. { - HCI_TRACE_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, wait_entry->opcode); + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + HCI_TRACE_ERROR("%s hci layer timeout waiting for response to a command. opcode: 0x%x", __func__, metadata->opcode); } } @@ -432,7 +412,8 @@ static void hal_says_adv_rpt_ready(pkt_linked_item_t *linked_pkt) // information, like how many commands are now able to be sent. static bool filter_incoming_event(BT_HDR *packet) { - waiting_command_t *wait_entry = NULL; + pkt_linked_item_t *wait_entry = NULL; + hci_cmd_metadata_t *metadata = NULL; uint8_t *stream = packet->data + packet->offset; uint8_t event_code; command_opcode_t opcode; @@ -446,10 +427,11 @@ static bool filter_incoming_event(BT_HDR *packet) STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); + metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); - } else if (wait_entry->complete_callback) { - wait_entry->complete_callback(packet, wait_entry->context); + } else if (metadata->command_complete_cb) { + metadata->command_complete_cb(packet, metadata->context); #if (BLE_50_FEATURE_SUPPORT == TRUE) BlE_SYNC *sync_info = btsnd_hcic_ble_get_sync_info(); if(!sync_info) { @@ -461,8 +443,8 @@ static bool filter_incoming_event(BT_HDR *packet) } } #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) - } else if (wait_entry->complete_future) { - future_ready(wait_entry->complete_future, packet); + } else if (metadata->flags_vnd & HCI_CMD_MSG_F_VND_FUTURE) { + future_ready((future_t *)(metadata->complete_future), packet); } goto intercepted; @@ -475,10 +457,11 @@ static bool filter_incoming_event(BT_HDR *packet) // If a command generates a command status event, it won't be getting a command complete event wait_entry = get_waiting_command(opcode); + metadata = (hci_cmd_metadata_t *)(wait_entry->data); if (!wait_entry) { HCI_TRACE_WARNING("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); - } else if (wait_entry->status_callback) { - wait_entry->status_callback(status, wait_entry->command, wait_entry->context); + } else if (metadata->command_status_cb) { + metadata->command_status_cb(status, &metadata->command, metadata->context); } goto intercepted; @@ -490,23 +473,22 @@ intercepted: /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && - !fixed_queue_is_empty(hci_host_env.command_queue)) { + !fixed_pkt_queue_is_empty(hci_host_env.command_queue)) { hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); } if (wait_entry) { // If it has a callback, it's responsible for freeing the packet if (event_code == HCI_COMMAND_STATUS_EVT || - (!wait_entry->complete_callback && !wait_entry->complete_future)) { + (!metadata->command_complete_cb && !metadata->complete_future)) { osi_free(packet); } // If it has a callback, it's responsible for freeing the command - if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) { - osi_free(wait_entry->command); + if (event_code == HCI_COMMAND_COMPLETE_EVT || !metadata->command_status_cb) { + hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func; + free_func(wait_entry); } - - osi_free(wait_entry); } else { osi_free(packet); } @@ -553,7 +535,7 @@ static serial_data_type_t event_to_data_type(uint16_t event) return 0; } -static waiting_command_t *get_waiting_command(command_opcode_t opcode) +static pkt_linked_item_t *get_waiting_command(command_opcode_t opcode) { command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT); @@ -561,15 +543,15 @@ static waiting_command_t *get_waiting_command(command_opcode_t opcode) for (const list_node_t *node = list_begin(cmd_wait_q->commands_pending_response); node != list_end(cmd_wait_q->commands_pending_response); node = list_next(node)) { - waiting_command_t *wait_entry = list_node(node); - if (!wait_entry || wait_entry->opcode != opcode) { - continue; + pkt_linked_item_t *wait_entry = list_node(node); + if (wait_entry) { + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + if (metadata->opcode == opcode) { + list_remove(cmd_wait_q->commands_pending_response, wait_entry); + osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); + return wait_entry; + } } - - list_remove(cmd_wait_q->commands_pending_response, wait_entry); - - osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); - return wait_entry; } osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock); diff --git a/components/bt/host/bluedroid/hci/hci_packet_factory.c b/components/bt/host/bluedroid/hci/hci_packet_factory.c index 7fd7f0ddb9..5010e99d2f 100644 --- a/components/bt/host/bluedroid/hci/hci_packet_factory.c +++ b/components/bt/host/bluedroid/hci/hci_packet_factory.c @@ -27,7 +27,6 @@ #include "hci/hci_packet_factory.h" -static BT_HDR *make_packet(size_t data_size); static BT_HDR *make_command_no_params(uint16_t opcode); static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out); @@ -234,7 +233,9 @@ static BT_HDR *make_command_no_params(uint16_t opcode) static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **stream_out) { - BT_HDR *packet = make_packet(HCI_COMMAND_PREAMBLE_SIZE + parameter_size); + BT_HDR *packet = HCI_GET_CMD_BUF(parameter_size); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(packet); + metadata->opcode = opcode; uint8_t *stream = packet->data; UINT16_TO_STREAM(stream, opcode); @@ -247,17 +248,6 @@ static BT_HDR *make_command(uint16_t opcode, size_t parameter_size, uint8_t **st return packet; } -static BT_HDR *make_packet(size_t data_size) -{ - BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + data_size); - assert(ret); - ret->event = 0; - ret->offset = 0; - ret->layer_specific = 0; - ret->len = data_size; - return ret; -} - static const hci_packet_factory_t interface = { make_reset, make_read_buffer_size, diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 6ba4ccd18c..728c4997a8 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -25,6 +25,7 @@ #include "osi/osi.h" #include "osi/future.h" #include "osi/thread.h" +#include "osi/pkt_queue.h" ///// LEGACY DEFINITIONS ///// @@ -47,6 +48,7 @@ /* Local Bluetooth Controller ID for BR/EDR */ #define LOCAL_BR_EDR_CONTROLLER_ID 0 +#define HCI_CMD_MSG_F_VND_FUTURE (0x01) ///// END LEGACY DEFINITIONS ///// typedef struct hci_hal_t hci_hal_t; diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 04af26e926..e00bff2b00 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -662,14 +662,13 @@ tBTM_DEV_STATUS_CB *BTM_RegisterForDeviceStatusNotif (tBTM_DEV_STATUS_CB *p_cb) tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len, UINT8 *p_param_buf, tBTM_VSC_CMPL_CB *p_cb) { - void *p_buf; + BT_HDR *p_buf; BTM_TRACE_EVENT ("BTM: BTM_VendorSpecificCommand: Opcode: 0x%04X, ParamLen: %i.", opcode, param_len); /* Allocate a buffer to hold HCI command plus the callback function */ - if ((p_buf = osi_malloc((UINT16)(sizeof(BT_HDR) + sizeof (tBTM_CMPL_CB *) + - param_len + HCIC_PREAMBLE_SIZE))) != NULL) { + if ((p_buf = HCI_GET_CMD_BUF(param_len)) != NULL) { /* Send the HCI command (opcode will be OR'd with HCI_GRP_VENDOR_SPECIFIC) */ btsnd_hcic_vendor_spec_cmd (p_buf, opcode, param_len, p_param_buf, (void *)p_cb); diff --git a/components/bt/host/bluedroid/stack/btm/btm_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c index 154b9e1e04..598ca13ffc 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/host/bluedroid/stack/btm/btm_inq.c @@ -2395,6 +2395,7 @@ tBTM_STATUS BTM_WriteEIR( BT_HDR *p_buff, BOOLEAN fec_required) if (controller_get_interface()->supports_extended_inquiry_response()) { BTM_TRACE_API("Write Extended Inquiry Response to controller\n"); btsnd_hcic_write_ext_inquiry_response (p_buff, fec_required); + osi_free(p_buff); return BTM_SUCCESS; } else { osi_free(p_buff); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index d9130bd254..2ce46ec1bf 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -43,6 +43,7 @@ #include "common/bt_trace.h" #include "osi/thread.h" +#include "osi/pkt_queue.h" //#include "osi/mutex.h" // TODO(zachoverflow): remove this horrible hack #include "stack/btu.h" @@ -451,15 +452,21 @@ void btu_hcif_send_cmd (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_buf) STREAM_TO_UINT16(opcode, stream); - // Eww...horrible hackery here - /* If command was a VSC, then extract command_complete callback */ - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC + assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf); + metadata->command_complete_cb = btu_hcif_command_complete_evt; + metadata->command_status_cb = btu_hcif_command_status_evt; + metadata->opcode = opcode; + + vsc_callback = metadata->context; + /* If command is not a VSC, then the context field should be empty */ + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) != HCI_GRP_VENDOR_SPECIFIC #if BLE_INCLUDED == TRUE - || (opcode == HCI_BLE_RAND) - || (opcode == HCI_BLE_ENCRYPT) + && (opcode != HCI_BLE_RAND) + && (opcode != HCI_BLE_ENCRYPT) #endif - ) { - vsc_callback = *((void **)(p_buf + 1)); + ) { + assert (vsc_callback == NULL); } hci_layer_get_interface()->transmit_command( @@ -472,6 +479,7 @@ void btu_hcif_send_cmd (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_buf) btu_check_bt_sleep (); #endif } + #if (BLE_50_FEATURE_SUPPORT == TRUE) UINT8 btu_hcif_send_cmd_sync (UINT8 controller_id, BT_HDR *p_buf) { @@ -492,15 +500,22 @@ UINT8 btu_hcif_send_cmd_sync (UINT8 controller_id, BT_HDR *p_buf) sync_info->opcode = opcode; - // Eww...horrible hackery here - /* If command was a VSC, then extract command_complete callback */ - if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC + assert (p_buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p_buf); + metadata->command_complete_cb = btu_hcif_command_complete_evt; + metadata->command_status_cb = btu_hcif_command_status_evt; + metadata->command_free_cb = NULL; + metadata->opcode = opcode; + + vsc_callback = metadata->context; + /* If command is not a VSC, then the context field should be empty */ + if ((opcode & HCI_GRP_VENDOR_SPECIFIC) != HCI_GRP_VENDOR_SPECIFIC #if BLE_INCLUDED == TRUE - || (opcode == HCI_BLE_RAND) - || (opcode == HCI_BLE_ENCRYPT) + && (opcode != HCI_BLE_RAND) + && (opcode != HCI_BLE_ENCRYPT) #endif - ) { - vsc_callback = *((void **)(p_buf + 1)); + ) { + assert (vsc_callback == NULL); } hci_layer_get_interface()->transmit_command( @@ -1434,7 +1449,11 @@ static void btu_hcif_command_status_evt_on_task(BT_HDR *event) stream, hack->context); - osi_free(hack->command); + // check the HCI command integrity: opcode + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(hack->command); + assert(metadata->opcode == opcode); + + HCI_FREE_CMD_BUF(hack->command); osi_free(event); } diff --git a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c index 50935f3be6..b816d0227b 100644 --- a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -33,7 +33,6 @@ #include #include -#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)osi_malloc(HCIC_PREAMBLE_SIZE + sizeof(BT_HDR) + paramlen)) #if (BLE_50_FEATURE_SUPPORT == TRUE) static BlE_SYNC ble_sync_info; @@ -557,19 +556,17 @@ BOOLEAN btsnd_hcic_ble_encrypt (UINT8 *key, UINT8 key_len, BT_HDR *p; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF(sizeof (void *) + - HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) { + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_ENCRYPT)) == NULL) { return (FALSE); } pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_ENCRYPT; - p->offset = sizeof(void *); - - *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ - pp += sizeof(void *); /* Skip over callback pointer */ + p->offset = 0; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->context = p_cmd_cplt_cback; UINT16_TO_STREAM (pp, HCI_BLE_ENCRYPT); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_ENCRYPT); @@ -596,18 +593,17 @@ BOOLEAN btsnd_hcic_ble_rand (void *p_cmd_cplt_cback) BT_HDR *p; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF(sizeof (void *) + - HCIC_PARAM_SIZE_BLE_RAND)) == NULL) { + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_RAND)) == NULL) { return (FALSE); } pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_RAND; - p->offset = sizeof(void *); + p->offset = 0; - *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ - pp += sizeof(void *); /* Skip over callback pointer */ + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->context = p_cmd_cplt_cback; UINT16_TO_STREAM (pp, HCI_BLE_RAND); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_RAND); @@ -1046,6 +1042,9 @@ BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num) p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL; p->offset = 0; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK; + UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL); UINT16_TO_STREAM (pp, num); diff --git a/components/bt/host/bluedroid/stack/hcic/hcicmds.c b/components/bt/host/bluedroid/stack/hcic/hcicmds.c index 3b52804408..0763937c9f 100644 --- a/components/bt/host/bluedroid/stack/hcic/hcicmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hcicmds.c @@ -35,8 +35,6 @@ #include "btm_int.h" /* Included for UIPC_* macro definitions */ -#define HCI_GET_CMD_BUF(paramlen) ((BT_HDR *)osi_malloc(HCIC_PREAMBLE_SIZE + sizeof(BT_HDR) + paramlen)) - BOOLEAN btsnd_hcic_inquiry(const LAP inq_lap, UINT8 duration, UINT8 response_cnt) { BT_HDR *p; @@ -1331,6 +1329,9 @@ BOOLEAN btsnd_hcic_host_num_xmitted_pkts (UINT8 num_handles, UINT16 *handle, p->len = HCIC_PREAMBLE_SIZE + 1 + (num_handles * 4); p->offset = 0; + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK; + UINT16_TO_STREAM (pp, HCI_HOST_NUM_PACKETS_DONE); UINT8_TO_STREAM (pp, p->len - HCIC_PREAMBLE_SIZE); @@ -1431,9 +1432,13 @@ BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat, #endif /* BTM_SSR_INCLUDED */ /**** Extended Inquiry Response Commands ****/ -void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req) +void btsnd_hcic_write_ext_inquiry_response (BT_HDR *buffer, UINT8 fec_req) { - BT_HDR *p = (BT_HDR *)buffer; + BT_HDR *p; + if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_EXT_INQ_RESP)) == NULL) { + return; + } + UINT8 *pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_EXT_INQ_RESP; @@ -1441,9 +1446,10 @@ void btsnd_hcic_write_ext_inquiry_response (void *buffer, UINT8 fec_req) UINT16_TO_STREAM (pp, HCI_WRITE_EXT_INQ_RESPONSE); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_EXT_INQ_RESP); - UINT8_TO_STREAM (pp, fec_req); + memcpy(pp, buffer->data + 4, p->len - 4); + btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p); } @@ -1862,17 +1868,17 @@ BOOLEAN btsnd_hcic_write_pagescan_type (UINT8 type) #error "HCI_CMD_POOL_BUF_SIZE must be larger than 268" #endif -void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, UINT8 len, +void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode, UINT8 len, UINT8 *p_data, void *p_cmd_cplt_cback) { - BT_HDR *p = (BT_HDR *)buffer; + BT_HDR *p = buffer; UINT8 *pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + len; - p->offset = sizeof(void *); + p->offset = 0; - *((void **)pp) = p_cmd_cplt_cback; /* Store command complete callback in buffer */ - pp += sizeof(void *); /* Skip over callback pointer */ + hci_cmd_metadata_t * metadata = HCI_GET_CMD_METAMSG(p); + metadata->context = p_cmd_cplt_cback; UINT16_TO_STREAM (pp, HCI_GRP_VENDOR_SPECIFIC | opcode); UINT8_TO_STREAM (pp, len); diff --git a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h index 8f85582869..9e4eda774f 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -19,9 +19,66 @@ #ifndef HCIMSGS_H #define HCIMSGS_H +#include #include "common/bt_target.h" #include "stack/hcidefs.h" #include "stack/bt_types.h" +#include "osi/pkt_queue.h" +#include "osi/allocator.h" + +#define HCI_CMD_BUF_TYPE_METADATA (0xa56e) + +#define HCI_CMD_MSG_F_SRC_NOACK (0x01) + +typedef void (*hci_cmd_cmpl_cb)(BT_HDR *response, void *context); +typedef void (*hci_cmd_stat_cb)(uint8_t status, BT_HDR *command, void *context); +typedef void (*hci_cmd_free_cb)(pkt_linked_item_t *linked_pkt); + +typedef struct { + uint8_t flags_src; + uint8_t flags_vnd; // used for downstream layer + uint16_t opcode; + hci_cmd_cmpl_cb command_complete_cb; + hci_cmd_stat_cb command_status_cb; + void *context; + void *complete_future; + hci_cmd_free_cb command_free_cb; + BT_HDR command; +} hci_cmd_metadata_t; + +#define HCI_CMD_METADATA_HDR_SIZE (sizeof(hci_cmd_metadata_t)) + +#define HCI_CMD_LINKED_BUF_SIZE(paramlen) (BT_PKT_LINKED_HDR_SIZE + HCI_CMD_METADATA_HDR_SIZE + HCIC_PREAMBLE_SIZE + (paramlen)) + +#define HCI_GET_CMD_METAMSG(cmd_ptr) (hci_cmd_metadata_t *)((void *)(cmd_ptr) - offsetof(hci_cmd_metadata_t, command)) +#define HCI_GET_CMD_LINKED_STRUCT(metadata_ptr) (pkt_linked_item_t *)((void *)(metadata_ptr) - offsetof(pkt_linked_item_t, data)) + +static inline BT_HDR *hci_get_cmd_buf(size_t param_len) +{ + pkt_linked_item_t *linked_pkt = osi_calloc(HCI_CMD_LINKED_BUF_SIZE(param_len)); + if (linked_pkt == NULL) { + return NULL; + } + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)linked_pkt->data; + BT_HDR *command = &metadata->command; + + command->layer_specific = HCI_CMD_BUF_TYPE_METADATA; + command->len = HCIC_PREAMBLE_SIZE + param_len; + command->offset = 0; + + return command; +} + +static inline void hci_free_cmd_buf(BT_HDR *buf) +{ + assert(buf->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(buf); + pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); + osi_free(linked_pkt); +} + +#define HCI_GET_CMD_BUF(param_len) hci_get_cmd_buf(param_len) +#define HCI_FREE_CMD_BUF(buf) hci_free_cmd_buf(buf) void bte_main_hci_send(BT_HDR *p_msg, UINT16 event); void bte_main_lpm_allow_bt_device_sleep(void); @@ -378,7 +435,7 @@ BOOLEAN btsnd_hcic_sniff_sub_rate(UINT16 handle, UINT16 max_lat, #endif /* BTM_SSR_INCLUDED */ /* Extended Inquiry Response */ -void btsnd_hcic_write_ext_inquiry_response(void *buffer, UINT8 fec_req); +void btsnd_hcic_write_ext_inquiry_response(BT_HDR *buffer, UINT8 fec_req); #define HCIC_PARAM_SIZE_EXT_INQ_RESP 241 @@ -641,7 +698,7 @@ BOOLEAN btsnd_hcic_write_inquiry_mode(UINT8 type); /* Write Inquiry #define HCID_GET_SCO_LEN(p) (*((UINT8 *)((p) + 1) + p->offset + 2)) -void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode, +void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode, UINT8 len, UINT8 *p_data, void *p_cmd_cplt_cback); From ca945e821187885c8e14c0c5dc73b25875e89612 Mon Sep 17 00:00:00 2001 From: Karl Wang Date: Wed, 20 Jul 2022 05:48:28 +0800 Subject: [PATCH 15/17] component/bt: allocate and use one static buffer for HCI adv flow control command --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 71 +++++++++++++++++-- components/bt/host/bluedroid/hci/hci_layer.c | 9 ++- .../bluedroid/hci/include/hci/hci_layer.h | 2 + .../bt/host/bluedroid/stack/hcic/hciblecmds.c | 20 ++++-- .../bluedroid/stack/include/stack/hcimsgs.h | 2 +- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 77cde40d5a..e55b2d99ef 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -72,6 +72,8 @@ typedef struct { osi_alarm_t *adv_flow_monitor; int adv_credits; int adv_credits_to_release; + pkt_linked_item_t *adv_fc_cmd_buf; + bool cmd_buf_in_use; #endif hci_hal_callbacks_t *callbacks; osi_thread_t *hci_h4_thread; @@ -92,6 +94,7 @@ static bool hci_upstream_data_post(uint32_t timeout); #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) static void hci_adv_flow_monitor(void *context); +static void hci_adv_flow_cmd_free_cb(pkt_linked_item_t *linked_pkt); #endif static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thread_t *task_thread) @@ -103,10 +106,13 @@ static bool hci_hal_env_init(const hci_hal_callbacks_t *upper_callbacks, osi_thr hci_hal_env.callbacks = (hci_hal_callbacks_t *)upper_callbacks; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_hal_env.adv_fc_cmd_buf = osi_calloc(HCI_CMD_LINKED_BUF_SIZE(HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)); + assert(hci_hal_env.adv_fc_cmd_buf != NULL); osi_mutex_new(&hci_hal_env.adv_flow_lock); osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); hci_hal_env.adv_credits = BLE_ADV_REPORT_FLOW_CONTROL_NUM; hci_hal_env.adv_credits_to_release = 0; + hci_hal_env.cmd_buf_in_use = false; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); hci_hal_env.adv_flow_monitor = osi_alarm_new("adv_fc_mon", hci_adv_flow_monitor, NULL, HCI_ADV_FLOW_MONITOR_PERIOD_MS); assert (hci_hal_env.adv_flow_monitor != NULL); @@ -138,10 +144,13 @@ static void hci_hal_env_deinit(void) hci_hal_env.upstream_data_ready = NULL; #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + hci_hal_env.cmd_buf_in_use = true; osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_free(hci_hal_env.adv_flow_monitor); hci_hal_env.adv_flow_monitor = NULL; osi_mutex_free(&hci_hal_env.adv_flow_lock); + osi_free(hci_hal_env.adv_fc_cmd_buf); + hci_hal_env.adv_fc_cmd_buf = NULL; #endif hci_hal_env.hci_h4_thread = NULL; @@ -296,7 +305,7 @@ int hci_adv_credits_prep_to_release(uint16_t num) hci_hal_env.adv_credits_to_release = credits_to_release; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); - if (credits_to_release == num) { + if (credits_to_release == num && num != 0) { osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_set(hci_hal_env.adv_flow_monitor, HCI_ADV_FLOW_MONITOR_PERIOD_MS); } @@ -319,15 +328,64 @@ static int hci_adv_credits_release(void) return credits_released; } +static int hci_adv_credits_release_rollback(uint16_t num) +{ + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + hci_hal_env.adv_credits -= num; + hci_hal_env.adv_credits_to_release += num; + assert(hci_hal_env.adv_credits >=0); + assert(hci_hal_env.adv_credits_to_release <= BLE_ADV_REPORT_FLOW_CONTROL_NUM); + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + + return num; +} + +static void hci_adv_flow_cmd_free_cb(pkt_linked_item_t *linked_pkt) +{ + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + hci_hal_env.cmd_buf_in_use = false; + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + hci_adv_credits_try_release(0); +} + +bool hci_adv_flow_try_send_command(uint16_t credits_released) +{ + bool sent = false; + bool use_static_buffer = false; + + /* first try using static buffer, then dynamic buffer */ + if (!hci_hal_env.cmd_buf_in_use) { + osi_mutex_lock(&hci_hal_env.adv_flow_lock, OSI_MUTEX_MAX_TIMEOUT); + if (!hci_hal_env.cmd_buf_in_use) { + hci_hal_env.cmd_buf_in_use = true; + use_static_buffer = true; + } + osi_mutex_unlock(&hci_hal_env.adv_flow_lock); + } + + if (use_static_buffer) { + hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(hci_hal_env.adv_fc_cmd_buf->data); + BT_HDR *static_buffer = &metadata->command; + metadata->command_free_cb = hci_adv_flow_cmd_free_cb; + sent = btsnd_hcic_ble_update_adv_report_flow_control(credits_released, static_buffer); + } else { + sent = btsnd_hcic_ble_update_adv_report_flow_control(credits_released, NULL); + } + + return sent; +} + int hci_adv_credits_try_release(uint16_t num) { int credits_released = 0; if (hci_adv_credits_prep_to_release(num) >= HCI_BLE_ADV_MIN_CREDITS_TO_RELEASE) { credits_released = hci_adv_credits_release(); - assert(credits_released >= 0); if (credits_released > 0) { - // TODO: handle the exception that the command is discarded due to heap exhaustion - btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + if (!hci_adv_flow_try_send_command(credits_released)) { + hci_adv_credits_release_rollback(credits_released); + } + } else { + assert (credits_released == 0); } } return credits_released; @@ -338,8 +396,9 @@ int hci_adv_credits_force_release(uint16_t num) hci_adv_credits_prep_to_release(num); int credits_released = hci_adv_credits_release(); if (credits_released > 0) { - // TODO: handle the exception that the command is discarded due to heap exhaustion - btsnd_hcic_ble_update_adv_report_flow_control(credits_released); + if (!hci_adv_flow_try_send_command(credits_released)) { + hci_adv_credits_release_rollback(credits_released); + } } return credits_released; diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index 8d79043dd4..dab99ad2b9 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -242,9 +242,12 @@ static void transmit_command( pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); + metadata->flags_vnd |= HCI_CMD_MSG_F_VND_QUEUED; + // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; + HCI_TRACE_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", metadata->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); @@ -259,7 +262,7 @@ static future_t *transmit_command_futured(BT_HDR *command) pkt_linked_item_t *linked_pkt = HCI_GET_CMD_LINKED_STRUCT(metadata); assert(command->layer_specific == HCI_CMD_BUF_TYPE_METADATA); - metadata->flags_vnd |= HCI_CMD_MSG_F_VND_FUTURE; + metadata->flags_vnd |= (HCI_CMD_MSG_F_VND_QUEUED | HCI_CMD_MSG_F_VND_FUTURE); future_t *future = future_new(); @@ -294,8 +297,10 @@ static void event_command_ready(fixed_pkt_queue_t *queue) command_waiting_response_t *cmd_wait_q = &hci_host_env.cmd_waiting_q; wait_entry = fixed_pkt_queue_dequeue(queue, FIXED_QUEUE_MAX_TIMEOUT); - hci_cmd_metadata_t *metadata = (hci_cmd_metadata_t *)(wait_entry->data); + metadata->flags_vnd |= HCI_CMD_MSG_F_VND_SENT; + metadata->flags_vnd &= ~HCI_CMD_MSG_F_VND_QUEUED; + if (metadata->flags_src & HCI_CMD_MSG_F_SRC_NOACK) { packet_fragmenter->fragment_and_dispatch(&metadata->command); hci_cmd_free_cb free_func = metadata->command_free_cb ? metadata->command_free_cb : (hci_cmd_free_cb) osi_free_func; diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index 728c4997a8..e090149a39 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -49,6 +49,8 @@ #define LOCAL_BR_EDR_CONTROLLER_ID 0 #define HCI_CMD_MSG_F_VND_FUTURE (0x01) +#define HCI_CMD_MSG_F_VND_QUEUED (0x02) +#define HCI_CMD_MSG_F_VND_SENT (0x04) ///// END LEGACY DEFINITIONS ///// typedef struct hci_hal_t hci_hal_t; diff --git a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c index b816d0227b..4369ecc2c8 100644 --- a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -1028,23 +1028,31 @@ BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets, UIN return TRUE; } -BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num) +BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num, BT_HDR *static_buf) { BT_HDR *p; UINT8 *pp; - if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)) == NULL) { - return (FALSE); + if (static_buf != NULL) { + p = static_buf; + } else { + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL)) == NULL) { + return (FALSE); + } } + hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); + metadata->flags_src = HCI_CMD_MSG_F_SRC_NOACK; + if (static_buf == p) { + assert(metadata->command_free_cb != NULL); + } + p->layer_specific = HCI_CMD_BUF_TYPE_METADATA; + pp = (UINT8 *)(p + 1); p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL; p->offset = 0; - hci_cmd_metadata_t *metadata = HCI_GET_CMD_METAMSG(p); - metadata->flags_src |= HCI_CMD_MSG_F_SRC_NOACK; - UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL); UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL); UINT16_TO_STREAM (pp, num); diff --git a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h index 9e4eda774f..44aa840945 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -939,7 +939,7 @@ BOOLEAN btsnd_hcic_read_authenticated_payload_tout(UINT16 handle); BOOLEAN btsnd_hcic_write_authenticated_payload_tout(UINT16 handle, UINT16 timeout); -BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num); +BOOLEAN btsnd_hcic_ble_update_adv_report_flow_control (UINT16 num, BT_HDR *static_buf); #if (BLE_50_FEATURE_SUPPORT == TRUE) BOOLEAN btsnd_hcic_ble_read_phy(UINT16 conn_handle); From 6ffe0a526291ec85fb34b3bcf660c0957a57cc40 Mon Sep 17 00:00:00 2001 From: wangmengyang Date: Thu, 21 Jul 2022 11:50:32 +0800 Subject: [PATCH 16/17] component/bt: consider to handle HCI LE Direct Advertising Report --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 2 +- components/bt/host/bluedroid/stack/btm/btm_ble_gap.c | 8 ++++++++ .../bt/host/bluedroid/stack/btm/include/btm_ble_int.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index e55b2d99ef..a8501a1771 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -268,7 +268,7 @@ bool host_recv_adv_packet(uint8_t *packet) { assert(packet); if(packet[0] == DATA_TYPE_EVENT && packet[1] == HCI_BLE_EVENT) { - if(packet[3] == HCI_BLE_ADV_PKT_RPT_EVT + if(packet[3] == HCI_BLE_ADV_PKT_RPT_EVT || packet[3] == HCI_BLE_DIRECT_ADV_EVT #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) || packet[3] == HCI_BLE_ADV_DISCARD_REPORT_EVT #endif diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index f1a96a497d..6976996e75 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -3481,6 +3481,8 @@ static void btm_adv_pkt_handler(void *arg) btm_ble_process_adv_pkt(p); } else if (ble_sub_code == HCI_BLE_ADV_DISCARD_REPORT_EVT) { btm_ble_process_adv_discard_evt(p); + } else if (ble_sub_code == HCI_BLE_DIRECT_ADV_EVT) { + btm_ble_process_direct_adv_pkt(p); } else { assert (0); } @@ -3794,6 +3796,12 @@ void btm_ble_process_adv_discard_evt(UINT8 *p) } #endif } + +void btm_ble_process_direct_adv_pkt(UINT8 *p) +{ + // TODO +} + /******************************************************************************* ** ** Function btm_ble_start_scan diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h index 125f513d4e..7201ade3ae 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h @@ -389,6 +389,7 @@ extern "C" { void btm_ble_timeout(TIMER_LIST_ENT *p_tle); void btm_ble_process_adv_pkt (UINT8 *p); void btm_ble_process_adv_discard_evt(UINT8 *p); +void btm_ble_process_direct_adv_pkt (UINT8 *p); bool btm_ble_adv_pkt_ready(void); bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt); void btm_ble_proc_scan_rsp_rpt (UINT8 *p); From 7b3d4d5074b96c81ff3619bcfc59810a711b911b Mon Sep 17 00:00:00 2001 From: Karl Wang Date: Fri, 22 Jul 2022 02:57:53 +0800 Subject: [PATCH 17/17] component/bt: use OSI utility "osi_event" for HCI downstream data processing --- components/bt/host/bluedroid/hci/hci_hal_h4.c | 2 +- components/bt/host/bluedroid/hci/hci_layer.c | 49 ++++++++++++------- .../bluedroid/hci/include/hci/hci_layer.h | 2 +- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index a8501a1771..a909361536 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -524,7 +524,7 @@ static void host_send_pkt_available_cb(void) { //Controller rx cache buffer is ready for receiving new host packet //Just Call Host main thread task to process pending packets. - hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); + hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } static int host_recv_pkt_cb(uint8_t *data, uint16_t len) diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index dab99ad2b9..3f67b84825 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -42,8 +42,10 @@ #define HCI_HOST_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 3) #define HCI_HOST_TASK_NAME "hciT" #define HCI_HOST_TASK_WORKQUEUE_NUM (2) -#define HCI_HOST_TASK_WORKQUEUE0_LEN (0) -#define HCI_HOST_TASK_WORKQUEUE1_LEN (5) +#define HCI_HOST_TASK_WORKQUEUE0_LEN (1) // for downstream datapath +#define HCI_HOST_TASK_WORKQUEUE1_LEN (1) // for upstream datapath + +#define HCI_DOWNSTREAM_DATA_QUEUE_IDX (0) typedef struct { bool timer_is_set; @@ -56,7 +58,7 @@ typedef struct { int command_credits; fixed_pkt_queue_t *command_queue; fixed_queue_t *packet_queue; - + struct osi_event *downstream_data_ready; command_waiting_response_t cmd_waiting_q; /* @@ -84,7 +86,7 @@ static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks; static int hci_layer_init_env(void); static void hci_layer_deinit_env(void); -static void hci_host_thread_handler(void *arg); +static void hci_downstream_data_handler(void *arg); static void event_command_ready(fixed_pkt_queue_t *queue); static void event_packet_ready(fixed_queue_t *queue); static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q); @@ -110,6 +112,8 @@ int hci_start_up(void) return -2; } + osi_event_bind(hci_host_env.downstream_data_ready, hci_host_thread, HCI_DOWNSTREAM_DATA_QUEUE_IDX); + packet_fragmenter->init(&packet_fragmenter_callbacks); hal->open(&hal_callbacks, hci_host_thread); @@ -134,10 +138,9 @@ void hci_shut_down(void) hci_host_thread = NULL; } - -bool hci_host_task_post(uint32_t timeout) +bool hci_downstream_data_post(uint32_t timeout) { - return osi_thread_post(hci_host_thread, hci_host_thread_handler, NULL, 0, timeout); + return osi_thread_post_event(hci_host_env.downstream_data_ready, timeout); } static int hci_layer_init_env(void) @@ -156,6 +159,10 @@ static int hci_layer_init_env(void) return -1; } + struct osi_event *event = osi_event_create(hci_downstream_data_handler, NULL); + assert(event != NULL); + hci_host_env.downstream_data_ready = event; + hci_host_env.packet_queue = fixed_queue_new(QUEUE_SIZE_MAX); if (hci_host_env.packet_queue) { fixed_queue_register_dequeue(hci_host_env.packet_queue, event_packet_ready); @@ -189,6 +196,9 @@ static void hci_layer_deinit_env(void) { command_waiting_response_t *cmd_wait_q; + osi_event_delete(hci_host_env.downstream_data_ready); + hci_host_env.downstream_data_ready = NULL; + if (hci_host_env.command_queue) { fixed_pkt_queue_free(hci_host_env.command_queue, (fixed_pkt_queue_free_cb)osi_free_func); } @@ -206,7 +216,7 @@ static void hci_layer_deinit_env(void) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) } -static void hci_host_thread_handler(void *arg) +static void hci_downstream_data_handler(void *arg) { /* * Previous task handles RX queue and two TX Queues, Since there is @@ -216,18 +226,19 @@ static void hci_host_thread_handler(void *arg) * All packets will be directly copied to single queue in driver layer with * H4 type header added (1 byte). */ - if (esp_vhci_host_check_send_available()) { + while (esp_vhci_host_check_send_available()) { /*Now Target only allowed one packet per TX*/ BT_HDR *pkt = packet_fragmenter->fragment_current_packet(); if (pkt != NULL) { packet_fragmenter->fragment_and_dispatch(pkt); - } else { - if (!fixed_pkt_queue_is_empty(hci_host_env.command_queue) && + } else if (!fixed_pkt_queue_is_empty(hci_host_env.command_queue) && hci_host_env.command_credits > 0) { - fixed_pkt_queue_process(hci_host_env.command_queue); - } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { - fixed_queue_process(hci_host_env.packet_queue); - } + fixed_pkt_queue_process(hci_host_env.command_queue); + } else if (!fixed_queue_is_empty(hci_host_env.packet_queue)) { + fixed_queue_process(hci_host_env.packet_queue); + } else { + // No downstream packet to send, stop processing + break; } } } @@ -252,7 +263,7 @@ static void transmit_command( BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT); - hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); + hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } @@ -273,7 +284,7 @@ static future_t *transmit_command_futured(BT_HDR *command) command->event = MSG_STACK_TO_HC_HCI_CMD; fixed_pkt_queue_enqueue(hci_host_env.command_queue, linked_pkt, FIXED_PKT_QUEUE_MAX_TIMEOUT); - hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); + hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); return future; } @@ -286,7 +297,7 @@ static void transmit_downward(uint16_t type, void *data) fixed_queue_enqueue(hci_host_env.packet_queue, data, FIXED_QUEUE_MAX_TIMEOUT); } - hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); + hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } @@ -479,7 +490,7 @@ intercepted: /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && !fixed_pkt_queue_is_empty(hci_host_env.command_queue)) { - hci_host_task_post(OSI_THREAD_MAX_TIMEOUT); + hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } if (wait_entry) { diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index e090149a39..8e822f0fea 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -102,7 +102,7 @@ const hci_t *hci_layer_get_interface(void); int hci_start_up(void); void hci_shut_down(void); -bool hci_host_task_post(uint32_t timeout); +bool hci_downstream_data_post(uint32_t timeout); #if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) int hci_adv_credits_prep_to_release(uint16_t num);