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