xref: /btstack/platform/wiced/btstack_uart_block_wiced.c (revision bdf6d26abc1b93e8c1e8665fb025fb5d370ff36e)
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 MATTHIAS
24  * RINGWALD 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 wiced_result_t btstack_uart_block_wiced_tx_worker_send_block(void * arg){
121     // wait for CTS to become low in manual flow control mode
122     if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){
123         while (platform_gpio_input_get(wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]) == WICED_TRUE){
124             wiced_rtos_delay_milliseconds(10);
125         }
126     }
127 
128     // blocking send
129     platform_uart_transmit_bytes(wiced_bt_uart_driver, tx_worker_data_buffer, tx_worker_data_size);
130 
131     // let transport know
132     btstack_run_loop_wiced_execute_code_on_main_thread(&btstack_uart_block_wiced_main_notify_block_send, NULL);
133     return WICED_SUCCESS;
134 }
135 
136 // executed on rx worker thread
137 static wiced_result_t btstack_uart_block_wiced_rx_worker_receive_block(void * arg){
138 
139     if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){
140         platform_gpio_output_low(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]);
141     }
142 
143 #ifdef WICED_UART_READ_DOES_NOT_RETURN_BYTES_READ
144     // older API passes in number of bytes to read (checked in 3.3.1 and 3.4.0)
145     platform_uart_receive_bytes(wiced_bt_uart_driver, rx_worker_read_buffer, rx_worker_read_size, WICED_NEVER_TIMEOUT);
146 #else
147     // newer API uses pointer to return number of read bytes
148     uint32_t bytes = rx_worker_read_size;
149     platform_uart_receive_bytes(wiced_bt_uart_driver, rx_worker_read_buffer, &bytes, WICED_NEVER_TIMEOUT);
150     // assumption: bytes = bytes_to_read as timeout is never
151 #endif
152 
153     if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_MANUAL && wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){
154         platform_gpio_output_high(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]);
155     }
156 
157     // let transport know
158     btstack_run_loop_wiced_execute_code_on_main_thread(&btstack_uart_block_wiced_main_notify_block_read, NULL);
159     return WICED_SUCCESS;
160 }
161 
162 static int btstack_uart_block_wiced_init(const btstack_uart_config_t * config){
163     uart_config = config;
164 
165     // determine flow control mode based on hardware config and uart config
166     if (uart_config->flowcontrol){
167 #ifdef WICED_BT_UART_MANUAL_CTS_RTS
168         btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_MANUAL;
169 #else
170         btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_UART;
171 #endif
172     } else {
173         btstack_flow_control_mode = BTSTACK_FLOW_CONTROL_OFF;
174     }
175     return 0;
176 }
177 
178 static int btstack_uart_block_wiced_open(void){
179 
180     // UART config
181     wiced_uart_config_t wiced_uart_config =
182     {
183         .baud_rate    = uart_config->baudrate,
184         .data_width   = DATA_WIDTH_8BIT,
185         .parity       = NO_PARITY,
186         .stop_bits    = STOP_BITS_1,
187     };
188 
189     if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_UART){
190         wiced_uart_config.flow_control = FLOW_CONTROL_CTS_RTS;
191     } else {
192         wiced_uart_config.flow_control = FLOW_CONTROL_DISABLED;
193     }
194     wiced_ring_buffer_t * ring_buffer = NULL;
195 
196     // configure HOST and DEVICE WAKE PINs
197     platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_HOST_WAKE], INPUT_HIGH_IMPEDANCE);
198     platform_gpio_init(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE], OUTPUT_PUSH_PULL);
199     platform_gpio_output_low(wiced_bt_control_pins[WICED_BT_PIN_DEVICE_WAKE]);
200 
201     /* Configure Reg Enable pin to output. Set to HIGH */
202     if (wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){
203         platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_POWER ], OUTPUT_OPEN_DRAIN_PULL_UP );
204         platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
205     }
206 
207     wiced_rtos_delay_milliseconds( 100 );
208 
209     // Configure RTS
210     if (wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]){
211         switch (btstack_flow_control_mode){
212             case BTSTACK_FLOW_CONTROL_OFF:
213                 // configure RTS pin as output and set to low - always on
214                 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS], OUTPUT_PUSH_PULL);
215                 platform_gpio_output_low(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]);
216                 break;
217             case BTSTACK_FLOW_CONTROL_UART:
218                 // configuration done by platform_uart_init
219                 break;
220             case BTSTACK_FLOW_CONTROL_MANUAL:
221                 // configure RTS pin as output and set to high - controlled by btstack_uart_block_wiced_rx_worker_receive_block
222                 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS], OUTPUT_PUSH_PULL);
223                 platform_gpio_output_high(wiced_bt_uart_pins[WICED_BT_PIN_UART_RTS]);
224                 break;
225         }
226     }
227 
228     // Configure CTS
229     if (wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS]){
230         switch (btstack_flow_control_mode){
231             case BTSTACK_FLOW_CONTROL_OFF:
232                 // don't care
233                 break;
234             case BTSTACK_FLOW_CONTROL_UART:
235                 // configuration done by platform_uart_init
236                 break;
237             case BTSTACK_FLOW_CONTROL_MANUAL:
238                 // configure CTS to input, pull-up
239                 platform_gpio_init(wiced_bt_uart_pins[WICED_BT_PIN_UART_CTS], INPUT_PULL_UP);
240                 break;
241         }
242     }
243 
244     // use ring buffer to allow to receive RX_RING_BUFFER_SIZE/2 addition bytes - not needed with hardware UART
245     if (btstack_flow_control_mode != BTSTACK_FLOW_CONTROL_UART){
246         ring_buffer_init((wiced_ring_buffer_t *) &rx_ring_buffer, (uint8_t*) rx_data, sizeof( rx_data ) );
247         ring_buffer = (wiced_ring_buffer_t *) &rx_ring_buffer;
248     }
249 
250     platform_uart_init( wiced_bt_uart_driver, wiced_bt_uart_peripheral, &wiced_uart_config, ring_buffer );
251 
252 
253     // Reset Bluetooth via RESET line. Fallback to toggling POWER otherwise
254     if ( wiced_bt_control_pins[ WICED_BT_PIN_RESET ]){
255         platform_gpio_init( wiced_bt_control_pins[ WICED_BT_PIN_RESET ], OUTPUT_PUSH_PULL );
256         platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
257 
258         platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
259         wiced_rtos_delay_milliseconds( 100 );
260         platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_RESET ] );
261     }
262     else if ( wiced_bt_control_pins[ WICED_BT_PIN_POWER ]){
263         platform_gpio_output_low( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
264         wiced_rtos_delay_milliseconds( 100 );
265         platform_gpio_output_high( wiced_bt_control_pins[ WICED_BT_PIN_POWER ] );
266     }
267 
268     // wait for Bluetooth to start up
269     wiced_rtos_delay_milliseconds( 500 );
270 
271     // create worker threads for rx/tx. only single request is posted to their queues
272     wiced_rtos_create_worker_thread(&tx_worker_thread, WICED_BT_UART_THREAD_PRIORITY, WICED_BT_UART_THREAD_STACK_SIZE, 1);
273     wiced_rtos_create_worker_thread(&rx_worker_thread, WICED_BT_UART_THREAD_PRIORITY, WICED_BT_UART_THREAD_STACK_SIZE, 1);
274 
275     // tx is ready
276     tx_worker_data_size = 0;
277     return 0;
278 }
279 
280 static int btstack_uart_block_wiced_close(void){
281     // not implemented
282     return 0;
283 }
284 
285 static void btstack_uart_block_wiced_set_block_received( void (*block_handler)(void)){
286     block_received = block_handler;
287 }
288 
289 static void btstack_uart_block_wiced_set_block_sent( void (*block_handler)(void)){
290     block_sent = block_handler;
291 }
292 
293 static int btstack_uart_block_wiced_set_baudrate(uint32_t baudrate){
294 
295 #if defined(_STM32F205RGT6_) || defined(STM32F40_41xxx) || defined(STM32F411xE) || (STM32F412xG)
296 
297     // directly use STM peripheral functions to change baud rate dynamically
298 
299     // set TX to high
300     log_info("set baud %u", (int) baudrate);
301     const platform_gpio_t* gpio = wiced_bt_uart_pins[WICED_BT_PIN_UART_TX];
302     platform_gpio_output_high(gpio);
303 
304     // reconfigure TX pin as GPIO
305     GPIO_InitTypeDef gpio_init_structure;
306     gpio_init_structure.GPIO_Speed = GPIO_Speed_50MHz;
307     gpio_init_structure.GPIO_Mode  = GPIO_Mode_OUT;
308     gpio_init_structure.GPIO_OType = GPIO_OType_PP;
309     gpio_init_structure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
310     gpio_init_structure.GPIO_Pin   = (uint32_t) ( 1 << gpio->pin_number );
311     GPIO_Init( gpio->port, &gpio_init_structure );
312 
313     // disable USART
314     USART_Cmd( wiced_bt_uart_peripheral->port, DISABLE );
315 
316     // setup init structure
317     USART_InitTypeDef uart_init_structure;
318     uart_init_structure.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
319     uart_init_structure.USART_BaudRate   = baudrate;
320     uart_init_structure.USART_WordLength = USART_WordLength_8b;
321     uart_init_structure.USART_StopBits   = USART_StopBits_1;
322     uart_init_structure.USART_Parity     = USART_Parity_No;
323 
324     if (btstack_flow_control_mode == BTSTACK_FLOW_CONTROL_UART){
325         uart_init_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;
326     } else {
327         uart_init_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
328     }
329     USART_Init(wiced_bt_uart_peripheral->port, &uart_init_structure);
330 
331     // enable USART again
332     USART_Cmd( wiced_bt_uart_peripheral->port, ENABLE );
333 
334     // set TX pin as USART again
335     gpio_init_structure.GPIO_Mode  = GPIO_Mode_AF;
336     GPIO_Init( gpio->port, &gpio_init_structure );
337 
338 #else
339     log_error("btstack_uart_block_wiced_set_baudrate not implemented for this WICED Platform");
340 #endif
341     return 0;
342 }
343 
344 static int btstack_uart_block_wiced_set_parity(int parity){
345     log_error("btstack_uart_block_wiced_set_parity not implemented");
346     return 0;
347 }
348 
349 static void btstack_uart_block_wiced_send_block(const uint8_t *buffer, uint16_t length){
350     // store in request
351     tx_worker_data_buffer = buffer;
352     tx_worker_data_size = length;
353     wiced_rtos_send_asynchronous_event(&tx_worker_thread, &btstack_uart_block_wiced_tx_worker_send_block, NULL);
354 }
355 
356 static void btstack_uart_block_wiced_receive_block(uint8_t *buffer, uint16_t len){
357     rx_worker_read_buffer = buffer;
358     rx_worker_read_size   = len;
359     wiced_rtos_send_asynchronous_event(&rx_worker_thread, &btstack_uart_block_wiced_rx_worker_receive_block, NULL);
360 }
361 
362 
363 // static void btstack_uart_block_wiced_set_sleep(uint8_t sleep){
364 // }
365 // static void btstack_uart_block_wiced_set_csr_irq_handler( void (*csr_irq_handler)(void)){
366 // }
367 
368 static const btstack_uart_block_t btstack_uart_block_wiced = {
369     /* int  (*init)(hci_transport_config_uart_t * config); */         &btstack_uart_block_wiced_init,
370     /* int  (*open)(void); */                                         &btstack_uart_block_wiced_open,
371     /* int  (*close)(void); */                                        &btstack_uart_block_wiced_close,
372     /* void (*set_block_received)(void (*handler)(void)); */          &btstack_uart_block_wiced_set_block_received,
373     /* void (*set_block_sent)(void (*handler)(void)); */              &btstack_uart_block_wiced_set_block_sent,
374     /* int  (*set_baudrate)(uint32_t baudrate); */                    &btstack_uart_block_wiced_set_baudrate,
375     /* int  (*set_parity)(int parity); */                             &btstack_uart_block_wiced_set_parity,
376     /* int  (*set_flowcontrol)(int flowcontrol); */                   NULL,
377     /* void (*receive_block)(uint8_t *buffer, uint16_t len); */       &btstack_uart_block_wiced_receive_block,
378     /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_block_wiced_send_block,
379     /* int (*get_supported_sleep_modes); */                           NULL,
380     /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */    NULL,
381     /* void (*set_wakeup_handler)(void (*handler)(void)); */          NULL,
382     NULL, NULL, NULL, NULL,
383 };
384 
385 const btstack_uart_block_t * btstack_uart_block_wiced_instance(void){
386     return &btstack_uart_block_wiced;
387 }
388