xref: /btstack/platform/wiced/btstack_uart_block_wiced.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
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
btstack_uart_block_wiced_main_notify_block_send(void * arg)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
btstack_uart_block_wiced_main_notify_block_read(void * arg)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;
btstack_uart_block_wiced_tx_worker_send_block(void * arg)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;
btstack_uart_block_wiced_rx_worker_receive_block(void * arg)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 
btstack_uart_block_wiced_init(const btstack_uart_config_t * config)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 
btstack_uart_block_wiced_open(void)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 
btstack_uart_block_wiced_close(void)284 static int btstack_uart_block_wiced_close(void){
285     // not implemented
286     return 0;
287 }
288 
btstack_uart_block_wiced_set_block_received(void (* block_handler)(void))289 static void btstack_uart_block_wiced_set_block_received( void (*block_handler)(void)){
290     block_received = block_handler;
291 }
292 
btstack_uart_block_wiced_set_block_sent(void (* block_handler)(void))293 static void btstack_uart_block_wiced_set_block_sent( void (*block_handler)(void)){
294     block_sent = block_handler;
295 }
296 
btstack_uart_block_wiced_set_baudrate(uint32_t baudrate)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 
btstack_uart_block_wiced_set_parity(int parity)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 
btstack_uart_block_wiced_send_block(const uint8_t * buffer,uint16_t length)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 
btstack_uart_block_wiced_receive_block(uint8_t * buffer,uint16_t len)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 
btstack_uart_block_wiced_instance(void)389 const btstack_uart_block_t * btstack_uart_block_wiced_instance(void){
390     return &btstack_uart_block_wiced;
391 }
392