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