1 /******************************************************************************
2 *
3 * Copyright (C) 2010-2014 Broadcom Corporation
4 *..Copyright 2018-2020 NXP
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19
20 /******************************************************************************
21 *
22 * Entry point for UWB_TASK
23 *
24 ******************************************************************************/
25 #include <string.h>
26
27 #include "uci_hmsgs.h"
28 #include "uci_log.h"
29 #include "uwa_dm_int.h"
30 #include "uwa_sys.h"
31 #include "uwb_api.h"
32 #include "uwb_gki.h"
33 #include "uwb_hal_api.h"
34 #include "uwb_int.h"
35 #include "uwb_osal_common.h"
36 #include "uwb_target.h"
37
38 /*******************************************************************************
39 **
40 ** Function uwb_start_timer
41 **
42 ** Description Start a timer for the specified amount of time.
43 ** NOTE: The timeout resolution is in SECONDS! (Even
44 ** though the timer structure field is ticks)
45 **
46 ** Returns void
47 **
48 *******************************************************************************/
uwb_start_timer(TIMER_LIST_ENT * p_tle,uint16_t type,uint32_t timeout)49 void uwb_start_timer(TIMER_LIST_ENT* p_tle, uint16_t type, uint32_t timeout) {
50 UWB_HDR* p_msg;
51
52 /* if timer list is currently empty, start periodic GKI timer */
53 if (uwb_cb.timer_queue.p_first == NULL) {
54 /* if timer starts on other than UWB task (scritp wrapper) */
55 if (phUwb_GKI_get_taskid() != UWB_TASK) {
56 /* post event to start timer in UWB task */
57 p_msg = (UWB_HDR*)phUwb_GKI_getbuf(UWB_HDR_SIZE);
58 if (p_msg != NULL) {
59 p_msg->event = BT_EVT_TO_START_TIMER;
60 phUwb_GKI_send_msg(UWB_TASK, UWB_MBOX_ID, p_msg);
61 }
62 } else {
63 /* Start uwb_task 1-sec resolution timer */
64 phUwb_GKI_start_timer(UWB_TIMER_ID, GKI_SECS_TO_TICKS(1), true);
65 }
66 }
67
68 phUwb_GKI_remove_from_timer_list(&uwb_cb.timer_queue, p_tle);
69
70 p_tle->event = type;
71 p_tle->ticks = timeout; /* Save the number of seconds for the timer */
72
73 phUwb_GKI_add_to_timer_list(&uwb_cb.timer_queue, p_tle);
74 }
75
76 /*******************************************************************************
77 **
78 ** Function uwb_remaining_time
79 **
80 ** Description Return amount of time to expire
81 **
82 ** Returns time in second
83 **
84 *******************************************************************************/
uwb_remaining_time(TIMER_LIST_ENT * p_tle)85 uint32_t uwb_remaining_time(TIMER_LIST_ENT* p_tle) {
86 return (phUwb_GKI_get_remaining_ticks(&uwb_cb.timer_queue, p_tle));
87 }
88
89 /*******************************************************************************
90 **
91 ** Function uwb_process_timer_evt
92 **
93 ** Description Process uwb GKI timer event
94 **
95 ** Returns void
96 **
97 *******************************************************************************/
uwb_process_timer_evt(void)98 void uwb_process_timer_evt(void) {
99 TIMER_LIST_ENT* p_tle;
100
101 phUwb_GKI_update_timer_list(&uwb_cb.timer_queue, 1);
102
103 while ((uwb_cb.timer_queue.p_first) && (!uwb_cb.timer_queue.p_first->ticks)) {
104 p_tle = uwb_cb.timer_queue.p_first;
105 phUwb_GKI_remove_from_timer_list(&uwb_cb.timer_queue, p_tle);
106
107 if (uwb_cb.uwb_state == UWB_STATE_W4_HAL_CLOSE ||
108 uwb_cb.uwb_state == UWB_STATE_NONE) {
109 return;
110 }
111 switch (p_tle->event) {
112 default:
113 UCI_TRACE_I("uwb_process_timer_evt: timer:0x%p event (0x%04x)", p_tle,
114 p_tle->event);
115 UCI_TRACE_W("uwb_process_timer_evt: unhandled timer event (0x%04x)",
116 p_tle->event);
117 }
118 }
119
120 /* if timer list is empty stop periodic GKI timer */
121 if (uwb_cb.timer_queue.p_first == NULL) {
122 phUwb_GKI_stop_timer(UWB_TIMER_ID, 0);
123 }
124 }
125
126 /*******************************************************************************
127 **
128 ** Function uwb_stop_timer
129 **
130 ** Description Stop a timer.
131 **
132 ** Returns void
133 **
134 *******************************************************************************/
uwb_stop_timer(TIMER_LIST_ENT * p_tle)135 void uwb_stop_timer(TIMER_LIST_ENT* p_tle) {
136 phUwb_GKI_remove_from_timer_list(&uwb_cb.timer_queue, p_tle);
137
138 /* if timer list is empty stop periodic GKI timer */
139 if (uwb_cb.timer_queue.p_first == NULL) {
140 phUwb_GKI_stop_timer(UWB_TIMER_ID, 0);
141 }
142 }
143
144 /*******************************************************************************
145 **
146 ** Function uwb_start_quick_timer
147 **
148 ** Description Start a timer for the specified amount of time.
149 ** NOTE: The timeout resolution depends on including modules.
150 ** QUICK_TIMER_TICKS_PER_SEC should be used to convert from
151 ** time to ticks.
152 **
153 **
154 ** Returns void
155 **
156 *******************************************************************************/
uwb_start_quick_timer(TIMER_LIST_ENT * p_tle,uint16_t type,uint32_t timeout)157 void uwb_start_quick_timer(TIMER_LIST_ENT* p_tle, uint16_t type,
158 uint32_t timeout) {
159 UCI_TRACE_I("uwb_start_quick_timer enter: timeout: %d", timeout);
160 UWB_HDR* p_msg;
161
162 /* if timer list is currently empty, start periodic GKI timer */
163 if (uwb_cb.quick_timer_queue.p_first == NULL) {
164 /* if timer starts on other than UWB task (scritp wrapper) */
165 if (phUwb_GKI_get_taskid() != UWB_TASK) {
166 /* post event to start timer in UWB task */
167 p_msg = (UWB_HDR*)phUwb_GKI_getbuf(UWB_HDR_SIZE);
168 if (p_msg != NULL) {
169 p_msg->event = BT_EVT_TO_START_QUICK_TIMER;
170 phUwb_GKI_send_msg(UWB_TASK, UWB_MBOX_ID, p_msg);
171 }
172 } else {
173 /* Quick-timer is required for LLCP */
174 phUwb_GKI_start_timer(
175 UWB_QUICK_TIMER_ID,
176 ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true);
177 }
178 }
179
180 phUwb_GKI_remove_from_timer_list(&uwb_cb.quick_timer_queue, p_tle);
181
182 p_tle->event = type;
183 p_tle->ticks = timeout; /* Save the number of ticks for the timer */
184
185 phUwb_GKI_add_to_timer_list(&uwb_cb.quick_timer_queue, p_tle);
186 }
187
188 /*******************************************************************************
189 **
190 ** Function uwb_stop_quick_timer
191 **
192 ** Description Stop a timer.
193 **
194 ** Returns void
195 **
196 *******************************************************************************/
uwb_stop_quick_timer(TIMER_LIST_ENT * p_tle)197 void uwb_stop_quick_timer(TIMER_LIST_ENT* p_tle) {
198 UCI_TRACE_I("uwb_stop_quick_timer: enter");
199 phUwb_GKI_remove_from_timer_list(&uwb_cb.quick_timer_queue, p_tle);
200
201 /* if timer list is empty stop periodic GKI timer */
202 if (uwb_cb.quick_timer_queue.p_first == NULL) {
203 phUwb_GKI_stop_timer(UWB_QUICK_TIMER_ID, 0);
204 }
205 }
206
207 /*******************************************************************************
208 **
209 ** Function uwb_process_quick_timer_evt
210 **
211 ** Description Process quick timer event
212 **
213 ** Returns void
214 **
215 *******************************************************************************/
uwb_process_quick_timer_evt(void)216 void uwb_process_quick_timer_evt(void) {
217 TIMER_LIST_ENT* p_tle;
218
219 if (uwb_cb.uwb_state == UWB_STATE_W4_HAL_CLOSE ||
220 uwb_cb.uwb_state == UWB_STATE_NONE) {
221 return;
222 }
223
224 phUwb_GKI_update_timer_list(&uwb_cb.quick_timer_queue, 1);
225
226 while ((uwb_cb.quick_timer_queue.p_first) &&
227 (!uwb_cb.quick_timer_queue.p_first->ticks)) {
228 p_tle = uwb_cb.quick_timer_queue.p_first;
229 phUwb_GKI_remove_from_timer_list(&uwb_cb.quick_timer_queue, p_tle);
230
231 switch (p_tle->event) {
232 case UWB_TTYPE_UCI_WAIT_RSP:
233 uwb_ucif_cmd_timeout();
234 break;
235 default:
236 UCI_TRACE_I(
237 "uwb_process_quick_timer_evt: unhandled timer event (0x%04x)",
238 p_tle->event);
239 break;
240 }
241 }
242
243 /* if timer list is empty stop periodic GKI timer */
244 if (uwb_cb.quick_timer_queue.p_first == NULL) {
245 phUwb_GKI_stop_timer(UWB_QUICK_TIMER_ID, 0);
246 }
247 }
248
249 /*******************************************************************************
250 **
251 ** Function uwb_task_shutdown_uwbc
252 **
253 ** Description Handle UWB shutdown
254 **
255 ** Returns nothing
256 **
257 *******************************************************************************/
uwb_task_shutdown_uwbc(void)258 void uwb_task_shutdown_uwbc(void) {
259 UWB_HDR* p_msg;
260
261 /* Free any messages still in the mbox */
262 while ((p_msg = (UWB_HDR*)phUwb_GKI_read_mbox(UWB_MBOX_ID)) != NULL) {
263 phUwb_GKI_freebuf(p_msg);
264 }
265 uwb_gen_cleanup();
266
267 uwb_set_state(UWB_STATE_W4_HAL_CLOSE);
268 uwb_cb.p_hal->close();
269
270 /* Stop the timers */
271 phUwb_GKI_stop_timer(UWB_TIMER_ID, 0);
272 phUwb_GKI_stop_timer(UWB_QUICK_TIMER_ID, 0);
273 phUwb_GKI_stop_timer(UWA_TIMER_ID, 0);
274 }
275
276 #define UWB_TASK_ARGS __attribute__((unused)) uint32_t arg
277
uwb_task(uint32_t arg)278 uint32_t uwb_task(__attribute__((unused)) uint32_t arg) {
279 uint16_t event;
280 UWB_HDR* p_msg;
281 bool free_buf;
282 /* Initialize the uwb control block */
283 memset(&uwb_cb, 0, sizeof(tUWB_CB));
284
285 UCI_TRACE_I("UWB_TASK started.");
286
287 /* main loop */
288 while (true) {
289 event = phUwb_GKI_wait(0xFFFF, 0);
290 if (event == EVENT_MASK(GKI_SHUTDOWN_EVT)) {
291 break;
292 }
293 /* Handle UWB_TASK_EVT_TRANSPORT_READY from UWB HAL */
294 if (event & UWB_TASK_EVT_TRANSPORT_READY) {
295 UCI_TRACE_I("UWB_TASK got UWB_TASK_EVT_TRANSPORT_READY.");
296
297 /* Reset the UWB controller. */
298 uwb_set_state(UWB_STATE_IDLE);
299 uwb_enabled(UWB_STATUS_OK, NULL);
300 }
301
302 if (event & UWB_MBOX_EVT_MASK) {
303 /* Process all incoming UCI messages */
304 while ((p_msg = (UWB_HDR*)phUwb_GKI_read_mbox(UWB_MBOX_ID)) != NULL) {
305 free_buf = true;
306
307 /* Determine the input message type. */
308 switch (p_msg->event & UWB_EVT_MASK) {
309 case BT_EVT_TO_UWB_UCI:
310 free_buf = uwb_ucif_process_event(p_msg);
311 break;
312
313 case BT_EVT_TO_START_TIMER:
314 /* Start uwb_task 1-sec resolution timer */
315 phUwb_GKI_start_timer(UWB_TIMER_ID, GKI_SECS_TO_TICKS(1), true);
316 break;
317
318 case BT_EVT_TO_START_QUICK_TIMER:
319 /* Quick-timer is required for LLCP */
320 phUwb_GKI_start_timer(
321 UWB_QUICK_TIMER_ID,
322 ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true);
323 break;
324
325 case BT_EVT_TO_UWB_MSGS:
326 uwb_main_handle_hal_evt((tUWB_HAL_EVT_MSG*)p_msg);
327 break;
328
329 default:
330 UCI_TRACE_E("uwb_task: unhandle mbox message, event=%04x",
331 p_msg->event);
332 break;
333 }
334
335 if (free_buf) {
336 phUwb_GKI_freebuf(p_msg);
337 }
338 }
339 }
340
341 /* Process gki timer tick */
342 if (event & UWB_TIMER_EVT_MASK) {
343 uwb_process_timer_evt();
344 }
345
346 /* Process quick timer tick */
347 if (event & UWB_QUICK_TIMER_EVT_MASK) {
348 uwb_process_quick_timer_evt();
349 }
350
351 if (event & UWA_MBOX_EVT_MASK) {
352 while ((p_msg = (UWB_HDR*)phUwb_GKI_read_mbox(UWA_MBOX_ID)) != NULL) {
353 uwa_sys_event(p_msg);
354 }
355 }
356
357 if (event & UWA_TIMER_EVT_MASK) {
358 uwa_sys_timer_update();
359 }
360 }
361
362 UCI_TRACE_I("uwb_task terminated");
363
364 phUwb_GKI_exit_task(phUwb_GKI_get_taskid());
365 return 0;
366 }
367