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