1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "common/bt_target.h"
8 #include <string.h>
9 #include "esp_bt_main.h"
10 #include "common/bt_trace.h"
11 #include "common/bt_defs.h"
12 #include "btc/btc_profile_queue.h"
13 #include "osi/list.h"
14 #include "osi/allocator.h"
15
16 #if BTC_PRF_QUEUE_INCLUDED
17 /*******************************************************************************
18 ** Local type definitions
19 *******************************************************************************/
20 /*******************************************************************************
21 ** Static variables
22 *******************************************************************************/
23
24 static list_t *connect_queue;
25
26 static const size_t MAX_REASONABLE_REQUESTS = 10;
27
28 /*******************************************************************************
29 ** Queue helper functions
30 *******************************************************************************/
31
queue_int_add(connect_node_t * p_param)32 static void queue_int_add(connect_node_t *p_param)
33 {
34 if (!connect_queue) {
35 connect_queue = list_new(osi_free_func);
36 assert(connect_queue != NULL);
37 }
38
39 // Sanity check to make sure we're not leaking connection requests
40 assert(list_length(connect_queue) < MAX_REASONABLE_REQUESTS);
41
42 for (const list_node_t *node = list_begin(connect_queue); node != list_end(connect_queue); node = list_next(node)) {
43 if (((connect_node_t *)list_node(node))->uuid == p_param->uuid) {
44 BTC_TRACE_DEBUG("%s dropping duplicate connect request for uuid: %04x", __func__, p_param->uuid);
45 return;
46 }
47 }
48
49 connect_node_t *p_node = osi_malloc(sizeof(connect_node_t));
50 assert(p_node != NULL);
51 memcpy(p_node, p_param, sizeof(connect_node_t));
52 list_append(connect_queue, p_node);
53 }
54
queue_int_advance(void)55 static void queue_int_advance(void)
56 {
57 if (connect_queue && !list_is_empty(connect_queue)) {
58 list_remove(connect_queue, list_front(connect_queue));
59 }
60 }
61
btc_profile_queue_handler(btc_msg_t * msg)62 void btc_profile_queue_handler(btc_msg_t *msg)
63 {
64 btc_prf_que_args_t *arg = (btc_prf_que_args_t *)(msg->arg);
65 switch (msg->act) {
66 case BTC_PRF_QUE_CONNECT:
67 queue_int_add(&(arg->connect_node));
68 break;
69
70 case BTC_PRF_QUE_ADVANCE:
71 queue_int_advance();
72 break;
73 }
74
75 if (esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_ENABLED) {
76 btc_queue_connect_next();
77 }
78 }
79
80 /*******************************************************************************
81 **
82 ** Function btc_queue_connect
83 **
84 ** Description Add a new connection to the queue and trigger the next
85 ** scheduled connection.
86 **
87 ** Returns BT_STATUS_SUCCESS if successful
88 **
89 *******************************************************************************/
btc_queue_connect(uint16_t uuid,const bt_bdaddr_t * bda,btc_connect_cb_t connect_cb)90 bt_status_t btc_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btc_connect_cb_t connect_cb)
91 {
92 btc_msg_t msg;
93 btc_prf_que_args_t arg;
94
95 msg.sig = BTC_SIG_API_CALL;
96 msg.pid = BTC_PID_PRF_QUE;
97 msg.act = BTC_PRF_QUE_CONNECT;
98
99 memset(&arg, 0, sizeof(btc_prf_que_args_t));
100 memcpy(&arg.connect_node.bda, bda, sizeof(bt_bdaddr_t));
101 arg.connect_node.uuid = uuid;
102 arg.connect_node.connect_cb = connect_cb;
103
104 return btc_transfer_context(&msg, &arg, sizeof(btc_prf_que_args_t), NULL, NULL);
105 }
106 /*******************************************************************************
107 **
108 ** Function btc_queue_advance
109 **
110 ** Description Clear the queue's busy status and advance to the next
111 ** scheduled connection.
112 **
113 ** Returns void
114 **
115 *******************************************************************************/
btc_queue_advance(void)116 void btc_queue_advance(void)
117 {
118 btc_msg_t msg;
119
120 msg.sig = BTC_SIG_API_CALL;
121 msg.pid = BTC_PID_PRF_QUE;
122 msg.act = BTC_PRF_QUE_ADVANCE;
123
124 btc_transfer_context(&msg, NULL, 0, NULL, NULL);
125 }
126
127 // This function dispatches the next pending connect request. It is called from
128 // stack_manager when the stack comes up.
btc_queue_connect_next(void)129 bt_status_t btc_queue_connect_next(void)
130 {
131 if (!connect_queue || list_is_empty(connect_queue)) {
132 return BT_STATUS_FAIL;
133 }
134
135 connect_node_t *p_head = list_front(connect_queue);
136
137 // If the queue is currently busy, we return success anyway,
138 // since the connection has been queued...
139 if (p_head->busy) {
140 return BT_STATUS_SUCCESS;
141 }
142
143 p_head->busy = true;
144 return p_head->connect_cb(&p_head->bda, p_head->uuid);
145 }
146
147
148 /*******************************************************************************
149 **
150 ** Function btc_queue_release
151 **
152 ** Description Free up all the queue nodes and set the queue head to NULL
153 **
154 ** Returns void
155 **
156 *******************************************************************************/
btc_queue_release(void)157 void btc_queue_release(void)
158 {
159 list_free(connect_queue);
160 connect_queue = NULL;
161 }
162
163 #endif /* if BTC_PRF_QUEUE_INCLUDED */
164