1 /*******************************************************************************
2 * \file cybt_bt_task.c
3 *
4 * \brief
5 * Implement BT task which handles HCI packet from HCI task, and timer interrupt.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2019 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24
25 #include "stdbool.h"
26
27 #include "cyabs_rtos.h"
28
29 #include "cybt_platform_task.h"
30 #include "cybt_platform_hci.h"
31 #include "cybt_platform_trace.h"
32
33 #include "wiced_bt_stack_platform.h"
34 #include "cybt_platform_config.h"
35 #include "cybt_platform_interface.h"
36
37 /******************************************************************************
38 * Constants
39 ******************************************************************************/
40 #define BT_TASK_QUEUE_UTIL_HIGH_THRESHHOLD (90)
41 #define DO_NOT_CLEAR (false)
42 #define CLEAR_CAUSE_EVENT (true)
43 #define WAIT_FOR_ANY (false)
44 #define WAIT_FOR_ALL (true)
45 #define NON_BLOCKING ((cy_time_t)0)
46 #define NOT_IN_ISR (false)
47 #define IN_ISR (true)
48 #define BT_TASK_EVENT (0x1)
49
50 /******************************************************************************
51 * Variables Definitions
52 ******************************************************************************/
53 __attribute__((aligned(4))) uint8_t packet_buffer[1024];
54 static uint32_t bt_task_dropped_packet_cnt = 0;
55 static cy_thread_t bt_task = 0;
56 static cy_queue_t bt_task_queue; //npal = 0;
57 static cy_event_t bt_task_event;
58
59 /******************************************************************************
60 * Function Declarations
61 ******************************************************************************/
62 extern void cybt_core_stack_init(void);
63 extern void host_stack_platform_interface_deinit(void);
64 extern uint16_t cybt_platform_get_event_id(void *event);
65 extern void cybt_platform_hci_post_stack_init(void);
66 extern bool cybt_platform_hci_process_if_coredump(uint8_t *p_data, uint32_t length);
67 extern void cybt_platform_exception_handler(cybt_exception_t error, uint8_t *info, uint32_t length);
68
69 /******************************************************************************
70 * Function Definitions
71 ******************************************************************************/
72 BTSTACK_PORTING_SECTION_BEGIN
task_queue_utilization(void)73 static uint8_t task_queue_utilization(void)
74 {
75 size_t item_cnt_in_queue = 0;
76 cy_rslt_t result;
77
78 result = cy_rtos_count_queue(&bt_task_queue, &item_cnt_in_queue);
79 if(CY_RSLT_SUCCESS != result)
80 {
81 return CYBT_INVALID_QUEUE_UTILIZATION;
82 }
83
84 return (item_cnt_in_queue * 100 / BTU_TASK_QUEUE_COUNT);
85 }
86 BTSTACK_PORTING_SECTION_END
87
88 BTSTACK_PORTING_SECTION_BEGIN
cybt_send_msg_to_bt_task(void * p_bt_msg,bool is_from_isr)89 cybt_result_t cybt_send_msg_to_bt_task(void *p_bt_msg,
90 bool is_from_isr
91 )
92 {
93 cy_rslt_t result;
94 uint8_t util_in_percentage = task_queue_utilization();
95
96 if(NULL == p_bt_msg /* npal || bt_task_queue == 0*/)
97 {
98 return CYBT_ERR_BADARG;
99 }
100
101 if((cybt_platform_get_event_id(p_bt_msg) == BT_EVT_CORE_HCI) && (BT_TASK_QUEUE_UTIL_HIGH_THRESHHOLD < util_in_percentage))
102 {
103 bt_task_dropped_packet_cnt++;
104 return CYBT_ERR_QUEUE_ALMOST_FULL;
105 }
106
107 result = cy_rtos_put_queue(&bt_task_queue, (void *) &p_bt_msg, 0, is_from_isr);
108
109 if(CY_RSLT_SUCCESS != result)
110 {
111 bt_task_dropped_packet_cnt++;
112 return CYBT_ERR_SEND_QUEUE_FAILED;
113 }
114
115 cy_rtos_setbits_event(&bt_task_event, BT_TASK_EVENT, is_from_isr);
116
117 return CYBT_SUCCESS;
118 }
119 BTSTACK_PORTING_SECTION_END
120
121 BTSTACK_PORTING_SECTION_BEGIN
handle_hci_rx_packet(void * event)122 static void handle_hci_rx_packet(void *event)
123 {
124 hci_packet_type_t pti;
125 uint32_t length;
126
127 if(0 == cybt_platfrom_hci_get_rx_fifo_count())
128 return;
129
130 if(CYBT_SUCCESS !=
131 cybt_platform_hci_read(event, &pti, &packet_buffer[0], &length))
132 return;
133
134 switch(pti)
135 {
136 case HCI_PACKET_TYPE_EVENT:
137 if(false == cybt_platform_hci_process_if_coredump(&packet_buffer[0], length))
138 {
139 /* If not core dump packet process through btstack */
140 wiced_bt_process_hci_events(&packet_buffer[0], length);
141 }
142 break;
143
144 case HCI_PACKET_TYPE_ACL:
145 wiced_bt_process_acl_data(&packet_buffer[0], length);
146 break;
147
148 case HCI_PACKET_TYPE_SCO:
149 //NA
150 break;
151 case HCI_PACKET_TYPE_ISO:
152 wiced_bt_process_isoc_data(&packet_buffer[0], length);
153 break;
154
155 #ifdef ENABLE_DEBUG_UART
156 case HCI_PACKET_TYPE_DIAG:
157 //sent packet to tracing uart
158 break;
159 #endif
160 default:
161 break;
162 }
163 }
164 BTSTACK_PORTING_SECTION_END
165
166 BTSTACK_PORTING_SECTION_BEGIN
bt_task_handler(cy_thread_arg_t arg)167 void bt_task_handler(cy_thread_arg_t arg)
168 {
169 cy_rslt_t result;
170 uint8_t is_stack_inited = 0;
171 uint16_t event_id;
172 size_t num_waiting;
173 uint32_t wait_for;
174 void* event = NULL;
175
176 cybt_platform_hci_open(arg);
177
178 for( ; ; )
179 {
180 event = NULL;
181
182 wait_for = BT_TASK_EVENT; // or with other events if we add anything
183
184 /* Blocking call for bt_task event */
185 cy_rtos_waitbits_event(&bt_task_event, &wait_for, CLEAR_CAUSE_EVENT, WAIT_FOR_ANY, CY_RTOS_NEVER_TIMEOUT);
186
187 if(BT_TASK_EVENT == (BT_TASK_EVENT & wait_for))
188 {
189 do{
190 cy_rtos_count_queue(&bt_task_queue, &num_waiting);
191 if( 0 == num_waiting )
192 break;
193
194 /* Non blocking call */
195 result = cy_rtos_get_queue(&bt_task_queue, &event, NON_BLOCKING, NOT_IN_ISR);
196
197 if(CY_RSLT_SUCCESS != result || (NULL == event))
198 {
199 BTTASK_TRACE_WARNING("bt_task(): event error (0x%x), event = 0x%p", result, event);
200 continue;
201 }
202
203 event_id = cybt_platform_get_event_id(event);
204
205 if(BT_EVT_TASK_SHUTDOWN == event_id)
206 {
207 BTTASK_TRACE_DEBUG("bt_task(): event:BT_EVT_TASK_SHUTDOWN");
208 cybt_platform_hci_close();
209 continue;
210 }
211 if (BT_EVT_TASK_RESET_COMPLETE == event_id)
212 {
213 BTTASK_TRACE_DEBUG("bt_task(): event:BT_EVT_TASK_RESET_COMPLETE");
214 /* Non blocking call */
215 while(CY_RSLT_SUCCESS == cy_rtos_get_queue(&bt_task_queue, &event, NON_BLOCKING, NOT_IN_ISR ))
216 {
217 }
218 cy_rtos_deinit_queue(&bt_task_queue);
219 cy_rtos_deinit_event(&bt_task_event);
220 wiced_bt_stack_shutdown();
221 is_stack_inited = 0;
222 host_stack_platform_interface_deinit();
223 cy_rtos_exit_thread();
224 return;
225 }
226
227 switch(event_id)
228 {
229 case BT_EVT_TIMEOUT:
230 wiced_bt_process_timer();
231 break;
232 case BT_EVT_CORE_HCI:
233 handle_hci_rx_packet(event);
234 break;
235 case BT_EVT_CORE_HCI_WRITE_BUF_AVAIL:
236 wiced_bt_stack_indicate_lower_tx_complete();
237 break;
238 case BT_EVT_TASK_BOOT_COMPLETES:
239 BTTASK_TRACE_DEBUG("bt_task(): controller core has been booted");
240 if(0 == is_stack_inited)
241 {
242 cybt_core_stack_init();
243 cybt_platform_hci_post_stack_init();
244 is_stack_inited = 1;
245 BTTASK_TRACE_DEBUG("bt_task(): stack initialization has been completed");
246 }
247 else
248 {
249 /* Reset might be due to controller crash. Don't deinit and init the host stack here.
250 * Let app decides this */
251 cybt_platform_exception_handler(CYBT_CONTROLLER_RESTARTED, NULL, 0);
252 }
253 break;
254 #if (defined(BTSTACK_VER) && (BTSTACK_VER >= 0x03080000))
255 case BT_EVT_APP_SERIALIZATION:
256 cybt_call_app_in_stack_context();
257 break;
258 #endif // BTSTACK_VER
259 default:
260 BTTASK_TRACE_ERROR("bt_task(): Unknown event (0x%x)", event_id);
261 break;
262 } //switch(*event)
263 }while(1);
264 }// if(BT_TASK_EVENT == (BT_TASK_EVENT & wait_for))
265 } // for(;;)
266 }
267 BTSTACK_PORTING_SECTION_END
268
cybt_bttask_init(void * p_arg)269 cybt_result_t cybt_bttask_init(void* p_arg)
270 {
271 cy_rslt_t cy_result;
272 cy_result = cy_rtos_init_event(&bt_task_event);
273 if(CY_RSLT_SUCCESS != cy_result)
274 {
275 BTTASK_TRACE_ERROR("task_init(): Init bt task event failed (0x%x)", cy_result);
276 return CYBT_ERR_INIT_EVENT_FAILED;
277 }
278
279 cy_result = cy_rtos_init_queue(&bt_task_queue,
280 BTU_TASK_QUEUE_COUNT,
281 BTU_TASK_QUEUE_ITEM_SIZE
282 );
283 if(CY_RSLT_SUCCESS != cy_result)
284 {
285 BTTASK_TRACE_ERROR("task_init(): Init bt task queue failed (0x%x)", cy_result);
286 return CYBT_ERR_INIT_QUEUE_FAILED;
287 }
288
289 cy_result = cy_rtos_create_thread(&bt_task,
290 bt_task_handler,
291 BT_TASK_NAME_BTU,
292 NULL,
293 BTU_TASK_STACK_SIZE,
294 BTU_TASK_PRIORITY,
295 p_arg
296 );
297 if(CY_RSLT_SUCCESS != cy_result)
298 {
299 BTTASK_TRACE_ERROR("task_init(): Create bt task failed (0x%x)", cy_result);
300 return CYBT_ERR_CREATE_TASK_FAILED;
301 }
302
303 return (CYBT_SUCCESS);
304 }
305
cybt_bttask_deinit(void)306 void cybt_bttask_deinit(void)
307 {
308 /* To clean up resources of older bt task instance.
309 * If we miss below call we will end up with CY_RTOS_NO_MEMORY for next thread create
310 * Below call will wait on internal semaphore and it will set on cy_rtos_exit_thread() */
311 cy_rtos_join_thread(&bt_task);
312 }
313
314