1 /*******************************************************************************
2 * \file cybt_platform_main.c
3 *
4 * \brief
5 * This file provides functions for WICED BT stack initialization.
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 "wiced_bt_dev.h"
26 #include "wiced_bt_cfg.h"
27 #include "wiced_bt_stack_platform.h"
28 #include "wiced_bt_stack.h"
29 #include "wiced_bt_gatt.h"
30 
31 #include "cybt_platform_task.h"
32 #include "cybt_platform_trace.h"
33 #include "cybt_platform_config.h"
34 #include "cybt_platform_interface.h"
35 #include "cybt_platform_util.h"
36 #include "cybt_platform_internal.h"
37 
38 /******************************************************************************
39  *                                Constants
40  ******************************************************************************/
41 #define HCI_VSC_WRITE_SLEEP_MODE             (0xFC27)
42 #define HCI_VSC_WRITE_SLEEP_MODE_LENGTH      (12)
43 
44 #define BT_SLEEP_MODE_ENABLE                 (1)
45 #define BT_SLEEP_THRESHOLD_HOST              (1)
46 #define BT_SLEEP_THRESHOLD_HOST_CONTROLLER   (1)
47 #define BT_SLEEP_ALLOW_HOST_SLEEP_DURING_SCO (1)
48 #define BT_SLEEP_COMBINE_SLEEP_MODE_AND_LPM  (1)
49 #define BT_SLEEP_ENABLE_UART_TXD_TRISTATE    (0)
50 #define BT_SLEEP_PULSED_HOST_WAKE            (0)
51 #define BT_SLEEP_SLEEP_GUARD_TIME            (0)
52 #define BT_SLEEP_WAKEUP_GUARD_TIME           (0)
53 #define BT_SLEEP_TXD_CONFIG                  (1)
54 #define BT_SLEEP_BT_WAKE_IDLE_TIME           (50)
55 
56 #define HCI_EVT_COREDUMPTYPE_END             (0xFF)  // Value for 'Core Dump End'
57 #define HCI_EVT_COREDUMPTYPE_INDEX           (6)     // Index for CoreDumpType
58 
59 #ifdef RESET_LOCAL_SUPPORT_FEATURE
60 #define CONNECTION_PARAMETER_REQUEST_PROCEDURE (1) // Feature bit position for Connection Parameters Request Procedure
61 #endif
62 
63 /*****************************************************************************
64  *                           Type Definitions
65  *****************************************************************************/
66 typedef struct
67 {
68     wiced_bt_management_cback_t   *p_app_management_callback;
69     const cybt_platform_config_t  *p_bt_platform_cfg;
70     bool                          is_sleep_mode_enabled;
71 } cybt_platform_main_cb_t;
72 
73 /******************************************************************************
74  *                           Variables Definitions
75  ******************************************************************************/
76 cybt_platform_main_cb_t cybt_main_cb = {0};
77 
78 
79 /******************************************************************************
80  *                          Function Declarations
81  ******************************************************************************/
82 extern void host_stack_platform_interface_init(void);
83 #ifdef ENABLE_DEBUG_UART
84 extern cybt_result_t cybt_send_coredump_hci_trace (uint16_t data_size, uint8_t *p_data);
85 #endif
86 
87 #ifdef RESET_LOCAL_SUPPORT_FEATURE
88 extern void wiced_bt_btm_ble_reset_local_supported_features(uint32_t feature);
89 #endif
90 
91 wiced_result_t cybt_core_management_cback( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data );
92 /******************************************************************************
93  *                           Function Definitions
94  ******************************************************************************/
bt_sleep_status_cback(wiced_bt_dev_vendor_specific_command_complete_params_t * p_command_complete_params)95 void bt_sleep_status_cback (wiced_bt_dev_vendor_specific_command_complete_params_t *p_command_complete_params)
96 {
97     MAIN_TRACE_DEBUG("bt_sleep_status_cback(): status = 0x%x",
98                      p_command_complete_params->p_param_buf[0]
99             );
100 
101     if(HCI_SUCCESS == p_command_complete_params->p_param_buf[0])
102     {
103         cybt_main_cb.is_sleep_mode_enabled = true;
104     }
105     else
106     {
107         cybt_main_cb.is_sleep_mode_enabled = false;
108     }
109 }
110 
bt_enable_sleep_mode(void)111 bool bt_enable_sleep_mode(void)
112 {
113     wiced_result_t result;
114     uint8_t        sleep_vsc[HCI_VSC_WRITE_SLEEP_MODE_LENGTH] = { 0 };
115     const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
116 
117     MAIN_TRACE_DEBUG("bt_enable_sleep_mode()");
118 
119     if( CYBT_HCI_UART == p_bt_platform_cfg->hci_config.hci_transport )
120     {
121         sleep_vsc[0] = BT_SLEEP_MODE_ENABLE;
122         sleep_vsc[1] = BT_SLEEP_THRESHOLD_HOST;
123         sleep_vsc[2] = BT_SLEEP_THRESHOLD_HOST_CONTROLLER;
124         sleep_vsc[3] = cybt_main_cb.p_bt_platform_cfg->controller_config.sleep_mode.device_wake_polarity;
125         sleep_vsc[4] = cybt_main_cb.p_bt_platform_cfg->controller_config.sleep_mode.host_wake_polarity;
126         sleep_vsc[5] = BT_SLEEP_ALLOW_HOST_SLEEP_DURING_SCO;
127         sleep_vsc[6] = BT_SLEEP_COMBINE_SLEEP_MODE_AND_LPM;
128         sleep_vsc[7] = BT_SLEEP_ENABLE_UART_TXD_TRISTATE;
129         sleep_vsc[8] = 0;
130         sleep_vsc[9] = 0;
131         sleep_vsc[10] = 0;
132         sleep_vsc[11] = BT_SLEEP_PULSED_HOST_WAKE;
133     }
134     else
135     {
136         memset(sleep_vsc, 0, sizeof(sleep_vsc));
137         sleep_vsc[0] = BT_SLEEP_MODE_ENABLE;
138     }
139 
140     result = wiced_bt_dev_vendor_specific_command(HCI_VSC_WRITE_SLEEP_MODE,
141                                                   HCI_VSC_WRITE_SLEEP_MODE_LENGTH,
142                                                   sleep_vsc,
143                                                   bt_sleep_status_cback
144                                                   );
145     if(WICED_BT_PENDING != result)
146     {
147         MAIN_TRACE_DEBUG("bt_enable_sleep_mode(): Fail to send vsc (0x%x)", result);
148         return false;
149     }
150 
151     return true;
152 }
153 
154 /*
155  * On stack initalization complete this call back gets called
156 */
wiced_post_stack_init_cback(void)157 void wiced_post_stack_init_cback( void )
158 {
159     wiced_bt_management_evt_data_t event_data;
160     const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
161     cybt_controller_sleep_config_t *p_sleep_config =
162             &(((cybt_platform_config_t *)cybt_main_cb.p_bt_platform_cfg)->controller_config.sleep_mode);
163 
164     MAIN_TRACE_DEBUG("wiced_post_stack_init_cback");
165 
166     memset(&event_data, 0, sizeof(wiced_bt_management_evt_t));
167     event_data.enabled.status = WICED_BT_SUCCESS;
168 
169     cybt_core_management_cback(BTM_ENABLED_EVT, &event_data);
170 #ifdef RESET_LOCAL_SUPPORT_FEATURE
171     wiced_bt_btm_ble_reset_local_supported_features(CONNECTION_PARAMETER_REQUEST_PROCEDURE);
172 #endif
173 
174     if(CYBT_SLEEP_MODE_ENABLED == p_sleep_config->sleep_mode_enabled)
175     {
176         bool status = false;
177         if( CYBT_HCI_UART == p_bt_platform_cfg->hci_config.hci_transport )
178         {
179             if((NC != p_sleep_config->device_wakeup_pin) && (NC != p_sleep_config->host_wakeup_pin))
180 
181             {
182                 status = ENABLE_SLEEP_MODE();
183             }
184             else
185             {
186                 MAIN_TRACE_ERROR("wiced_post_stack_init_cback(): BT sleep mode is NOT enabled");
187                 return;
188             }
189         }
190         else
191         {
192             status = ENABLE_SLEEP_MODE();
193         }
194 
195         if(false == status)
196         {
197             MAIN_TRACE_ERROR("wiced_post_stack_init_cback(): Fail to init sleep mode");
198         }
199     }
200     else
201     {
202         MAIN_TRACE_ERROR("wiced_post_stack_init_cback(): BT sleep mode is NOT enabled");
203     }
204 }
205 
206 /*
207 * This call back gets called for each HCI event.
208 */
wiced_stack_event_handler_cback(uint8_t * p_event)209 wiced_bool_t wiced_stack_event_handler_cback (uint8_t *p_event)
210 {
211     return WICED_FALSE;
212 }
213 
214 
215 
216 #if (defined(BTSTACK_VER) && (BTSTACK_VER >= 0x03070000))
init_layers(void)217 static wiced_result_t init_layers(void)
218 {
219     /* handle in porting layer */
220     return wiced_bt_smp_module_init();
221 }
222 
223 #if (defined(__GNUC__) || defined(__ARMCC_VERSION))
app_initialize_btstack_modules(void)224 extern __attribute__((weak)) wiced_result_t app_initialize_btstack_modules(void)
225 {
226      return init_layers();
227 }
228 #endif
229 
230 #if defined(__ICCARM__)
231 extern wiced_result_t app_initialize_btstack_modules(void);
232 #pragma weak app_initialize_btstack_modules=init_layers
233 
234 #endif
235 #endif // BTSTACK_VER
236 
cybt_core_management_cback(wiced_bt_management_evt_t event,wiced_bt_management_evt_data_t * p_event_data)237 wiced_result_t cybt_core_management_cback( wiced_bt_management_evt_t event, wiced_bt_management_evt_data_t *p_event_data )
238 {
239     wiced_result_t result = WICED_BT_SUCCESS;
240     int send_to_app = 1;
241 
242 #if (defined(BTSTACK_VER) && (BTSTACK_VER >= 0x03070000))
243     switch(event)
244     {
245         case BTM_ENABLED_EVT:
246             #ifndef DISABLE_DEFAULT_BTSTACK_INIT
247             app_initialize_btstack_modules();
248             #endif
249 
250             wiced_bt_init_resolution(); /* to be removed subsequently. only required for non-privacy controllers */
251         break;
252     }
253 #endif // BTSTACK_VER
254 
255     if(send_to_app && cybt_main_cb.p_app_management_callback)
256     {
257         result = cybt_main_cb.p_app_management_callback(event, p_event_data);
258     }
259 
260     return result;
261 }
262 
cybt_core_stack_init(void)263 void cybt_core_stack_init(void)
264 {
265     /* Start the stack */
266     wiced_bt_stack_init_internal(cybt_core_management_cback,
267                                  wiced_post_stack_init_cback,
268                                  wiced_stack_event_handler_cback
269                                  );
270 }
271 
wiced_bt_stack_init(wiced_bt_management_cback_t * p_bt_management_cback,const wiced_bt_cfg_settings_t * p_bt_cfg_settings)272 wiced_result_t wiced_bt_stack_init(wiced_bt_management_cback_t *p_bt_management_cback,
273                                    const wiced_bt_cfg_settings_t *p_bt_cfg_settings
274                                    )
275 {
276     MAIN_TRACE_DEBUG("wiced_bt_stack_init()");
277 
278     cybt_main_cb.is_sleep_mode_enabled = false;
279 
280     cybt_platform_init();
281 
282     cybt_main_cb.p_app_management_callback = p_bt_management_cback;
283 
284     host_stack_platform_interface_init();
285 
286     /* Configure the stack */
287     if (0 == wiced_bt_set_stack_config(p_bt_cfg_settings))
288     {
289         MAIN_TRACE_ERROR("wiced_bt_set_stack_config(): Failed\n");
290     }
291 
292     cybt_platform_task_init((void *)p_bt_cfg_settings);
293 
294     return WICED_BT_SUCCESS;
295 }
296 
wiced_bt_stack_deinit(void)297 wiced_result_t wiced_bt_stack_deinit( void )
298 {
299     cybt_platform_task_deinit();
300 
301     cybt_platform_deinit();
302 
303     return WICED_BT_SUCCESS;
304 }
305 
cybt_platform_config_init(const cybt_platform_config_t * p_bt_platform_cfg)306 void cybt_platform_config_init(const cybt_platform_config_t *p_bt_platform_cfg)
307 {
308     MAIN_TRACE_DEBUG("cybt_platform_config_init()");
309 
310     cybt_main_cb.p_bt_platform_cfg = p_bt_platform_cfg;
311 }
312 
cybt_platform_get_sleep_mode_status(void)313 bool cybt_platform_get_sleep_mode_status(void)
314 {
315     return cybt_main_cb.is_sleep_mode_enabled;
316 }
317 
cybt_platform_get_config(void)318 const cybt_platform_config_t* cybt_platform_get_config(void)
319 {
320     return cybt_main_cb.p_bt_platform_cfg;
321 }
322 
trace_exception(cybt_exception_t error,uint8_t * info,uint32_t length)323 static void trace_exception(cybt_exception_t error, uint8_t *info, uint32_t length)
324 {
325     switch (error)
326     {
327         case CYBT_HCI_IPC_REL_BUFFER:
328             MAIN_TRACE_ERROR("Exception: case: IPC release buffer failed, reason:0x%x", *(uint32_t *)info);
329             break;
330         case CYBT_CONTROLLER_RESTARTED:
331             MAIN_TRACE_ERROR("Exception: case: BT restarted again");
332             break;
333         case CYBT_CONTROLLER_CORE_DUMP:
334             MAIN_TRACE_ERROR("Exception: case: %x [CoreDump], len:%d reason:0x%x", error, length, *(uint32_t *)info);
335 
336 #ifdef ENABLE_DEBUG_UART
337             cybt_send_coredump_hci_trace(length, &info[0]);
338 #else
339             for (uint32_t i = 0; i < length; i++)
340             {
341                 MAIN_TRACE_ERROR("%x ", *(uint8_t *)(info + i));
342             }
343 #endif
344 
345             if(HCI_EVT_COREDUMPTYPE_END == *(uint8_t *)(info + HCI_EVT_COREDUMPTYPE_INDEX))
346             {
347                 MAIN_TRACE_ERROR("End of CoreDump. Going to Assert ");
348                 cy_rtos_delay_milliseconds(10);
349                 CY_ASSERT(0);
350             }
351             break;
352         default:
353             MAIN_TRACE_ERROR("Exception: case: %x [unknown]", error);
354             break;
355     }
356 }
357 
cybt_platform_exception_handler(cybt_exception_t error,uint8_t * info,uint32_t length)358 void cybt_platform_exception_handler(cybt_exception_t error, uint8_t *info, uint32_t length)
359 {
360     trace_exception(error, info, length);
361 
362 #if 0 // Todo: register handler from app then enable this code
363     /* If app callback is not registered on exception, trigger assert */
364     if ( NULL == exception_cb )
365     {
366         CY_ASSERT(0);
367     }
368 
369     /* If app not handled on exception, trigger assert */
370     if( false == exception_cb(error, info, length) )
371     {
372         CY_ASSERT(0);
373     }
374 #else
375     /* We might get more core dump packets. Do not assert from here. */
376     if(CYBT_CONTROLLER_CORE_DUMP != error)
377         CY_ASSERT(0);
378 #endif
379     return;
380 }
381 
382