1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2020 Damien P. George
7  * Copyright (c) 2020 Jim Mussared
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 
28 #include "py/runtime.h"
29 #include "py/mperrno.h"
30 #include "py/mphal.h"
31 
32 #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
33 
34 #include "lib/btstack/src/btstack.h"
35 
36 #include "extmod/mpbthci.h"
37 #include "extmod/btstack/btstack_hci_uart.h"
38 
39 #include "mpbtstackport.h"
40 
41 #define HCI_TRACE (0)
42 #define COL_OFF "\033[0m"
43 #define COL_GREEN "\033[0;32m"
44 #define COL_BLUE "\033[0;34m"
45 
46 // Implements a btstack btstack_uart_block_t on top of the mphciuart.h
47 // interface to an HCI UART provided by the port.
48 
49 // We pass the bytes directly to the UART during a send, but then notify btstack in the next poll.
50 STATIC bool send_done;
51 STATIC void (*send_handler)(void);
52 
53 // btstack issues a read of len bytes, and gives us a buffer to asynchronously fill up.
54 STATIC uint8_t *recv_buf;
55 STATIC size_t recv_len;
56 STATIC size_t recv_idx;
57 STATIC void (*recv_handler)(void);
58 STATIC bool init_success = false;
59 
btstack_uart_init(const btstack_uart_config_t * uart_config)60 STATIC int btstack_uart_init(const btstack_uart_config_t *uart_config) {
61     (void)uart_config;
62 
63     send_done = false;
64     recv_len = 0;
65     recv_idx = 0;
66     recv_handler = NULL;
67     send_handler = NULL;
68 
69     // Set up the UART peripheral, attach IRQ and power up the HCI controller.
70     if (mp_bluetooth_hci_uart_init(MICROPY_HW_BLE_UART_ID, MICROPY_HW_BLE_UART_BAUDRATE)) {
71         init_success = false;
72         return -1;
73     }
74     if (mp_bluetooth_hci_controller_init()) {
75         init_success = false;
76         return -1;
77     }
78 
79     init_success = true;
80     return 0;
81 }
82 
btstack_uart_open(void)83 STATIC int btstack_uart_open(void) {
84     return init_success ? 0 : 1;
85 }
86 
btstack_uart_close(void)87 STATIC int btstack_uart_close(void) {
88     mp_bluetooth_hci_controller_deinit();
89     mp_bluetooth_hci_uart_deinit();
90     return 0;
91 }
92 
btstack_uart_set_block_received(void (* block_handler)(void))93 STATIC void btstack_uart_set_block_received(void (*block_handler)(void)) {
94     recv_handler = block_handler;
95 }
96 
btstack_uart_set_block_sent(void (* block_handler)(void))97 STATIC void btstack_uart_set_block_sent(void (*block_handler)(void)) {
98     send_handler = block_handler;
99 }
100 
btstack_uart_set_baudrate(uint32_t baudrate)101 STATIC int btstack_uart_set_baudrate(uint32_t baudrate) {
102     mp_bluetooth_hci_uart_set_baudrate(baudrate);
103     return 0;
104 }
105 
btstack_uart_set_parity(int parity)106 STATIC int btstack_uart_set_parity(int parity) {
107     (void)parity;
108     return 0;
109 }
110 
btstack_uart_set_flowcontrol(int flowcontrol)111 STATIC int btstack_uart_set_flowcontrol(int flowcontrol) {
112     (void)flowcontrol;
113     return 0;
114 }
115 
btstack_uart_receive_block(uint8_t * buf,uint16_t len)116 STATIC void btstack_uart_receive_block(uint8_t *buf, uint16_t len) {
117     recv_buf = buf;
118     recv_len = len;
119 }
120 
btstack_uart_send_block(const uint8_t * buf,uint16_t len)121 STATIC void btstack_uart_send_block(const uint8_t *buf, uint16_t len) {
122     #if HCI_TRACE
123     printf(COL_GREEN "< [% 8d] %02x", (int)mp_hal_ticks_ms(), buf[0]);
124     for (size_t i = 1; i < len; ++i) {
125         printf(":%02x", buf[i]);
126     }
127     printf(COL_OFF "\n");
128     #endif
129 
130     mp_bluetooth_hci_uart_write(buf, len);
131     send_done = true;
132 }
133 
btstack_uart_get_supported_sleep_modes(void)134 STATIC int btstack_uart_get_supported_sleep_modes(void) {
135     return 0;
136 }
137 
btstack_uart_set_sleep(btstack_uart_sleep_mode_t sleep_mode)138 STATIC void btstack_uart_set_sleep(btstack_uart_sleep_mode_t sleep_mode) {
139     (void)sleep_mode;
140     // printf("btstack_uart_set_sleep %u\n", sleep_mode);
141 }
142 
btstack_uart_set_wakeup_handler(void (* wakeup_handler)(void))143 STATIC void btstack_uart_set_wakeup_handler(void (*wakeup_handler)(void)) {
144     (void)wakeup_handler;
145     // printf("btstack_uart_set_wakeup_handler\n");
146 }
147 
148 const btstack_uart_block_t mp_bluetooth_btstack_hci_uart_block = {
149     &btstack_uart_init,
150     &btstack_uart_open,
151     &btstack_uart_close,
152     &btstack_uart_set_block_received,
153     &btstack_uart_set_block_sent,
154     &btstack_uart_set_baudrate,
155     &btstack_uart_set_parity,
156     &btstack_uart_set_flowcontrol,
157     &btstack_uart_receive_block,
158     &btstack_uart_send_block,
159     &btstack_uart_get_supported_sleep_modes,
160     &btstack_uart_set_sleep,
161     &btstack_uart_set_wakeup_handler,
162 };
163 
mp_bluetooth_btstack_hci_uart_process(void)164 void mp_bluetooth_btstack_hci_uart_process(void) {
165     bool host_wake = mp_bluetooth_hci_controller_woken();
166 
167     if (send_done) {
168         // If we'd done a TX in the last interval, notify btstack that it's complete.
169         send_done = false;
170         if (send_handler) {
171             send_handler();
172         }
173     }
174 
175     // Append any new bytes to the recv buffer, notifying bstack if we've got
176     // the number of bytes it was looking for.
177     int chr;
178     while (recv_idx < recv_len && (chr = mp_bluetooth_hci_uart_readchar()) >= 0) {
179         recv_buf[recv_idx++] = chr;
180         if (recv_idx == recv_len) {
181             #if HCI_TRACE
182             printf(COL_BLUE "> [% 8d] %02x", (int)mp_hal_ticks_ms(), recv_buf[0]);
183             for (size_t i = 1; i < recv_len; ++i) {
184                 printf(":%02x", recv_buf[i]);
185             }
186             printf(COL_OFF "\n");
187             #endif
188             recv_idx = 0;
189             recv_len = 0;
190             if (recv_handler) {
191                 recv_handler();
192             }
193         }
194     }
195 
196     if (host_wake) {
197         mp_bluetooth_hci_controller_sleep_maybe();
198     }
199 }
200 
201 #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
202