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