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