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