1 /* 2 * Copyright (C) 2015 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 /* 39 * hci_h4_transport_wiced.c 40 * 41 * HCI Transport API implementation for basic H4 protocol for use with btstack_run_loop_wiced.c 42 */ 43 44 #define BTSTACK_FILE__ "btstack_uart_block_wiced.c" 45 46 #include "btstack_config.h" 47 #include "btstack_debug.h" 48 #include "btstack_run_loop_wiced.h" 49 #include "btstack_uart_block.h" 50 51 #include "hci.h" 52 #include "hci_transport.h" 53 #include "platform_bluetooth.h" 54 55 #include "wiced.h" 56 57 #include <stdio.h> 58 #include <string.h> 59 60 // priority higher than WIFI to make sure RTS is set 61 #define WICED_BT_UART_THREAD_PRIORITY (WICED_NETWORK_WORKER_PRIORITY - 2) 62 #define WICED_BT_UART_THREAD_STACK_SIZE 300 63 64 // assert pre-buffer for packet type is available 65 #if !defined(HCI_OUTGOING_PRE_BUFFER_SIZE) || (HCI_OUTGOING_PRE_BUFFER_SIZE == 0) 66 #error HCI_OUTGOING_PRE_BUFFER_SIZE not defined. Please update hci.h 67 #endif 68 69 // Default of 512 bytes should be fine. Only needed with BTSTACK_FLOW_CONTROL_UART 70 #ifndef RX_RING_BUFFER_SIZE 71 #define RX_RING_BUFFER_SIZE 512 72 #endif 73 74 // Use BTSTACK_FLOW_CONTROL_MANUAL is used when Bluetooth RTS/CTS are not connected to UART RTS/CTS pins 75 // E.g. on RedBear Duo - WICED_BT_UART_MANUAL_CTS_RTS is defined 76 77 static enum { 78 BTSTACK_FLOW_CONTROL_OFF, 79 BTSTACK_FLOW_CONTROL_UART, 80 BTSTACK_FLOW_CONTROL_MANUAL, 81 } btstack_flow_control_mode; 82 83 static wiced_result_t btstack_uart_block_wiced_rx_worker_receive_block(void * arg); 84 85 static wiced_worker_thread_t tx_worker_thread; 86 static const uint8_t * tx_worker_data_buffer; 87 static uint16_t tx_worker_data_size; 88 89 static wiced_worker_thread_t rx_worker_thread; 90 static uint8_t * rx_worker_read_buffer; 91 static uint16_t rx_worker_read_size; 92 93 static wiced_ring_buffer_t rx_ring_buffer; 94 static uint8_t rx_data[RX_RING_BUFFER_SIZE]; 95 96 // uart config 97 static const btstack_uart_config_t * uart_config; 98 99 // callbacks 100 static void (*block_sent)(void); 101 static void (*block_received)(void); 102 103 // executed on main run loop 104 static wiced_result_t btstack_uart_block_wiced_main_notify_block_send(void *arg){ 105 if (block_sent){ 106 block_sent(); 107 } 108 return WICED_SUCCESS; 109 } 110 111 // executed on main run loop 112 static wiced_result_t btstack_uart_block_wiced_main_notify_block_read(void *arg){ 113 if (block_received){ 114 block_received(); 115 } 116 return WICED_SUCCESS; 117 } 118 119 // executed on tx worker thread 120 static btstack_context_callback_registration_t block_send_callback_registration; 121 static wiced_result_t btstack_uart_block_wiced_tx_worker_send_block(void * arg){ 122 // wait for CTS to become low in manual flow control mode 123 if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){ 124 while (platform_gpio_input_get(wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]) == WICED_TRUE){ 125 wiced_rtos_delay_milliseconds(10); 126 } 127 } 128 129 // blocking send 130 platform_uart_transmit_bytes(wiced_bt_uart_driver, tx_worker_data_buffer, tx_worker_data_size); 131 132 // let transport know 133 block_send_callback_registration.callback = &btstack_uart_block_wiced_main_notify_block_send; 134 btstack_run_loop_execute_on_main_thread(&block_send_callback_registration); 135 return WICED_SUCCESS; 136 } 137 138 // executed on rx worker thread 139 static btstack_context_callback_registration_t block_received_callback_registration; 140 static wiced_result_t btstack_uart_block_wiced_rx_worker_receive_block(void * arg){ 141 142 if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){ 143 platform_gpio_output_low(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); 144 } 145 146 #ifdef WICED_UART_READ_DOES_NOT_RETURN_BYTES_READ 147 // older API passes in number of bytes to read (checked in 3.3.1 and 3.4.0) 148 platform_uart_receive_bytes(wiced_bt_uart_driver, rx_worker_read_buffer, rx_worker_read_size, WICED_NEVER_TIMEOUT); 149 #else 150 // newer API uses pointer to return number of read bytes 151 uint32_t bytes = rx_worker_read_size; 152 platform_uart_receive_bytes(wiced_bt_uart_driver, rx_worker_read_buffer, &bytes, WICED_NEVER_TIMEOUT); 153 // assumption: bytes = bytes_to_read as timeout is never 154 #endif 155 156 if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){ 157 platform_gpio_output_high(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); 158 } 159 160 // let transport know 161 block_received_callback_registration.callback = &btstack_uart_block_wiced_main_notify_block_read; 162 btstack_run_loop_execute_on_main_thread(&block_received_callback_registration); 163 return WICED_SUCCESS; 164 } 165 166 static int btstack_uart_block_wiced_init(const btstack_uart_config_t * config){ 167 uart_config = config; 168 169 // determine flow control mode based on hardware config and uart config 170 if (uart_config->flowcontrol){ 171 #ifdef WICED_BT_UART_MANUAL_CTS_RTS 172 btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_MANUAL; 173 #else 174 btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_UART; 175 #endif 176 } else { 177 btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_OFF; 178 } 179 return 0; 180 } 181 182 static int btstack_uart_block_wiced_open(void){ 183 184 // UART config 185 wiced_uart_config_t wiced_uart_config = 186 { 187 .baud_rate = uart_config->baudrate, 188 .data_width = DATA_WIDTH_8BIT, 189 .parity = NO_PARITY, 190 .stop_bits = STOP_BITS_1, 191 }; 192 193 if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_UART){ 194 wiced_uart_config.flow_control = FLOW_CONTROL_CTS_RTS; 195 } else { 196 wiced_uart_config.flow_control = FLOW_CONTROL_DISABLED; 197 } 198 wiced_ring_buffer_t * ring_buffer = NULL; 199 200 // configure HOST and DEVICE WAKE PINs 201 platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_HOST_WAKE], INPUT_HIGH_IMPEDANCE); 202 platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE], OUTPUT_PUSH_PULL); 203 platform_gpio_output_low(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE]); 204 205 /* Configure Reg Enable pin to output. Set to HIGH */ 206 if (wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){ 207 platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_POWER ], OUTPUT_OPEN_DRAIN_PULL_UP ); 208 platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] ); 209 } 210 211 wiced_rtos_delay_milliseconds( 100 ); 212 213 // Configure RTS 214 if (wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]){ 215 switch (btstack_flow_control_mode){ 216 case BTSTACK_FLOW_CONTROL_OFF: 217 // configure RTS pin as output and set to low - always on 218 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS], OUTPUT_PUSH_PULL); 219 platform_gpio_output_low(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); 220 break; 221 case BTSTACK_FLOW_CONTROL_UART: 222 // configuration done by platform_uart_init 223 break; 224 case BTSTACK_FLOW_CONTROL_MANUAL: 225 // configure RTS pin as output and set to high - controlled by btstack_uart_block_wiced_rx_worker_receive_block 226 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS], OUTPUT_PUSH_PULL); 227 platform_gpio_output_high(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]); 228 break; 229 } 230 } 231 232 // Configure CTS 233 if (wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){ 234 switch (btstack_flow_control_mode){ 235 case BTSTACK_FLOW_CONTROL_OFF: 236 // don't care 237 break; 238 case BTSTACK_FLOW_CONTROL_UART: 239 // configuration done by platform_uart_init 240 break; 241 case BTSTACK_FLOW_CONTROL_MANUAL: 242 // configure CTS to input, pull-up 243 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS], INPUT_PULL_UP); 244 break; 245 } 246 } 247 248 // use ring buffer to allow to receive RX_RING_BUFFER_SIZE/2 addition bytes - not needed with hardware UART 249 if (btstack_flow_control_mode != BTSTACK_FLOW_CONTROL_UART){ 250 ring_buffer_init((wiced_ring_buffer_t *) &rx_ring_buffer, (uint8_t*) rx_data, sizeof( rx_data ) ); 251 ring_buffer = (wiced_ring_buffer_t *) &rx_ring_buffer; 252 } 253 254 platform_uart_init( wiced_bt_uart_driver, wiced_bt_uart_peripheral, &wiced_uart_config, ring_buffer ); 255 256 257 // Reset Bluetooth via RESET line. Fallback to toggling POWER otherwise 258 if ( wiced_bt_control_pins[ WICED_BT_PIN_RESET ]){ 259 platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_RESET ], OUTPUT_PUSH_PULL ); 260 platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] ); 261 262 platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] ); 263 wiced_rtos_delay_milliseconds( 100 ); 264 platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] ); 265 } 266 else if ( wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){ 267 platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] ); 268 wiced_rtos_delay_milliseconds( 100 ); 269 platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] ); 270 } 271 272 // wait for Bluetooth to start up 273 wiced_rtos_delay_milliseconds( 500 ); 274 275 // create worker threads for rx/tx. only single request is posted to their queues 276 wiced_rtos_create_worker_thread(&tx_worker_thread, WICED_BT_UART_THREAD_PRIORITY, WICED_BT_UART_THREAD_STACK_SIZE, 1); 277 wiced_rtos_create_worker_thread(&rx_worker_thread, WICED_BT_UART_THREAD_PRIORITY, WICED_BT_UART_THREAD_STACK_SIZE, 1); 278 279 // tx is ready 280 tx_worker_data_size = 0; 281 return 0; 282 } 283 284 static int btstack_uart_block_wiced_close(void){ 285 // not implemented 286 return 0; 287 } 288 289 static void btstack_uart_block_wiced_set_block_received( void (*block_handler)(void)){ 290 block_received = block_handler; 291 } 292 293 static void btstack_uart_block_wiced_set_block_sent( void (*block_handler)(void)){ 294 block_sent = block_handler; 295 } 296 297 static int btstack_uart_block_wiced_set_baudrate(uint32_t baudrate){ 298 299 #if defined(_STM32F205RGT6_) || defined(STM32F40_41xxx) || defined(STM32F411xE) || (STM32F412xG) 300 301 // directly use STM peripheral functions to change baud rate dynamically 302 303 // set TX to high 304 log_info("set baud %u", (int) baudrate); 305 const platform_gpio_t* gpio = wiced_bt_uart_pins[WICED_BT_PIN_UART_TX]; 306 platform_gpio_output_high(gpio); 307 308 // reconfigure TX pin as GPIO 309 GPIO_InitTypeDef gpio_init_structure; 310 gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz; 311 gpio_init_structure.GPIO_Mode = GPIO_Mode_OUT; 312 gpio_init_structure.GPIO_OType = GPIO_OType_PP; 313 gpio_init_structure.GPIO_PuPd = GPIO_PuPd_NOPULL; 314 gpio_init_structure.GPIO_Pin = (uint32_t) ( 1 << gpio->pin_number ); 315 GPIO_Init( gpio->port, &gpio_init_structure ); 316 317 // disable USART 318 USART_Cmd( wiced_bt_uart_peripheral->port, DISABLE ); 319 320 // setup init structure 321 USART_InitTypeDef uart_init_structure; 322 uart_init_structure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 323 uart_init_structure.USART_BaudRate = baudrate; 324 uart_init_structure.USART_WordLength = USART_WordLength_8b; 325 uart_init_structure.USART_StopBits = USART_StopBits_1; 326 uart_init_structure.USART_Parity = USART_Parity_No; 327 328 if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_UART){ 329 uart_init_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS; 330 } else { 331 uart_init_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 332 } 333 USART_Init(wiced_bt_uart_peripheral->port, &uart_init_structure); 334 335 // enable USART again 336 USART_Cmd( wiced_bt_uart_peripheral->port, ENABLE ); 337 338 // set TX pin as USART again 339 gpio_init_structure.GPIO_Mode = GPIO_Mode_AF; 340 GPIO_Init( gpio->port, &gpio_init_structure ); 341 342 #else 343 log_error("btstack_uart_block_wiced_set_baudrate not implemented for this WICED Platform"); 344 #endif 345 return 0; 346 } 347 348 static int btstack_uart_block_wiced_set_parity(int parity){ 349 log_error("btstack_uart_block_wiced_set_parity not implemented"); 350 return 0; 351 } 352 353 static void btstack_uart_block_wiced_send_block(const uint8_t *buffer, uint16_t length){ 354 // store in request 355 tx_worker_data_buffer = buffer; 356 tx_worker_data_size = length; 357 wiced_rtos_send_asynchronous_event(&tx_worker_thread, &btstack_uart_block_wiced_tx_worker_send_block, NULL); 358 } 359 360 static void btstack_uart_block_wiced_receive_block(uint8_t *buffer, uint16_t len){ 361 rx_worker_read_buffer = buffer; 362 rx_worker_read_size = len; 363 wiced_rtos_send_asynchronous_event(&rx_worker_thread, &btstack_uart_block_wiced_rx_worker_receive_block, NULL); 364 } 365 366 367 // static void btstack_uart_block_wiced_set_sleep(uint8_t sleep){ 368 // } 369 // static void btstack_uart_block_wiced_set_csr_irq_handler( void (*csr_irq_handler)(void)){ 370 // } 371 372 static const btstack_uart_block_t btstack_uart_block_wiced = { 373 /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_block_wiced_init, 374 /* int (*open)(void); */ &btstack_uart_block_wiced_open, 375 /* int (*close)(void); */ &btstack_uart_block_wiced_close, 376 /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_block_wiced_set_block_received, 377 /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_block_wiced_set_block_sent, 378 /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_block_wiced_set_baudrate, 379 /* int (*set_parity)(int parity); */ &btstack_uart_block_wiced_set_parity, 380 /* int (*set_flowcontrol)(int flowcontrol); */ NULL, 381 /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_block_wiced_receive_block, 382 /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_block_wiced_send_block, 383 /* int (*get_supported_sleep_modes); */ NULL, 384 /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL, 385 /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL, 386 NULL, NULL, NULL, NULL, 387 }; 388 389 const btstack_uart_block_t * btstack_uart_block_wiced_instance(void){ 390 return &btstack_uart_block_wiced; 391 } 392