1 /*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2018-2019 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 #include "py/runtime.h"
28 #include "py/mphal.h"
29 #include "nimble/ble.h"
30 #include "extmod/nimble/modbluetooth_nimble.h"
31 #include "extmod/nimble/hal/hal_uart.h"
32 #include "extmod/nimble/nimble/nimble_npl_os.h"
33 #include "extmod/mpbthci.h"
34
35 #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
36
37 #define HCI_TRACE (0)
38
39 static hal_uart_tx_cb_t hal_uart_tx_cb;
40 static void *hal_uart_tx_arg;
41 static hal_uart_rx_cb_t hal_uart_rx_cb;
42 static void *hal_uart_rx_arg;
43
44 // Provided by the port, and also possibly shared with the driver.
45 extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
46
hal_uart_init_cbs(uint32_t port,hal_uart_tx_cb_t tx_cb,void * tx_arg,hal_uart_rx_cb_t rx_cb,void * rx_arg)47 int hal_uart_init_cbs(uint32_t port, hal_uart_tx_cb_t tx_cb, void *tx_arg, hal_uart_rx_cb_t rx_cb, void *rx_arg) {
48 hal_uart_tx_cb = tx_cb;
49 hal_uart_tx_arg = tx_arg;
50 hal_uart_rx_cb = rx_cb;
51 hal_uart_rx_arg = rx_arg;
52 return 0; // success
53 }
54
hal_uart_config(uint32_t port,uint32_t baudrate,uint32_t bits,uint32_t stop,uint32_t parity,uint32_t flow)55 int hal_uart_config(uint32_t port, uint32_t baudrate, uint32_t bits, uint32_t stop, uint32_t parity, uint32_t flow) {
56 return mp_bluetooth_hci_uart_init(port, baudrate);
57 }
58
hal_uart_start_tx(uint32_t port)59 void hal_uart_start_tx(uint32_t port) {
60 size_t len = 0;
61 for (;;) {
62 int data = hal_uart_tx_cb(hal_uart_tx_arg);
63 if (data == -1) {
64 break;
65 }
66 mp_bluetooth_hci_cmd_buf[len++] = data;
67 }
68
69 #if HCI_TRACE
70 printf("< [% 8d] %02x", (int)mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]);
71 for (size_t i = 1; i < len; ++i) {
72 printf(":%02x", mp_bluetooth_hci_cmd_buf[i]);
73 }
74 printf("\n");
75 #endif
76
77 mp_bluetooth_hci_uart_write(mp_bluetooth_hci_cmd_buf, len);
78
79 if (len > 0) {
80 // Allow modbluetooth bindings to hook "sent packet" (e.g. to unstall l2cap channels).
81 mp_bluetooth_nimble_sent_hci_packet();
82 }
83 }
84
hal_uart_close(uint32_t port)85 int hal_uart_close(uint32_t port) {
86 return 0; // success
87 }
88
mp_bluetooth_nimble_hci_uart_process(bool run_events)89 void mp_bluetooth_nimble_hci_uart_process(bool run_events) {
90 bool host_wake = mp_bluetooth_hci_controller_woken();
91
92 int chr;
93 while ((chr = mp_bluetooth_hci_uart_readchar()) >= 0) {
94 #if HCI_TRACE
95 printf("> %02x\n", chr);
96 #endif
97 hal_uart_rx_cb(hal_uart_rx_arg, chr);
98
99 // Incoming data may result in events being enqueued. If we're in
100 // scheduler context then we can run those events immediately.
101 if (run_events) {
102 mp_bluetooth_nimble_os_eventq_run_all();
103 }
104 }
105
106 if (host_wake) {
107 mp_bluetooth_hci_controller_sleep_maybe();
108 }
109 }
110
111 #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
112