diff --git a/extmod/modbluetooth_hci.h b/extmod/modbluetooth_hci.h index 6d44761a4e..d6b432d224 100644 --- a/extmod/modbluetooth_hci.h +++ b/extmod/modbluetooth_hci.h @@ -50,6 +50,7 @@ extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj; int mp_bluetooth_hci_uart_init(uint32_t port); int mp_bluetooth_hci_uart_activate(void); int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate); +int mp_bluetooth_hci_uart_readchar(void); int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len); #endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_HCI_H diff --git a/extmod/nimble/nimble/npl_os.c b/extmod/nimble/nimble/npl_os.c index 57ab689e6b..620dcb0aec 100644 --- a/extmod/nimble/nimble/npl_os.c +++ b/extmod/nimble/nimble/npl_os.c @@ -235,7 +235,11 @@ ble_npl_error_t ble_npl_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout if (sem->count == 0) { uint32_t t0 = mp_hal_ticks_ms(); while (sem->count == 0 && mp_hal_ticks_ms() - t0 < timeout) { + // This function may be called at thread-level, so execute + // mp_bluetooth_nimble_hci_uart_process at raised priority. + MICROPY_PY_BLUETOOTH_ENTER mp_bluetooth_nimble_hci_uart_process(); + MICROPY_PY_BLUETOOTH_EXIT if (sem->count != 0) { break; } diff --git a/ports/stm32/btstack.c b/ports/stm32/btstack.c index f7669d1fc6..cbb15a86cb 100644 --- a/ports/stm32/btstack.c +++ b/ports/stm32/btstack.c @@ -165,8 +165,9 @@ STATIC void btstack_uart_process(void) { // Append any new bytes to the recv buffer, notifying bstack if we've got // the number of bytes it was looking for. - while (uart_rx_any(&mp_bluetooth_hci_uart_obj) && recv_idx < recv_len) { - recv_buf[recv_idx++] = uart_rx_char(&mp_bluetooth_hci_uart_obj); + int chr; + while (recv_idx < recv_len && (chr = mp_bluetooth_hci_uart_readchar()) >= 0) { + recv_buf[recv_idx++] = chr; if (recv_idx == recv_len) { recv_idx = 0; recv_len = 0; diff --git a/ports/stm32/modbluetooth_hci.c b/ports/stm32/modbluetooth_hci.c index c6937b2b2a..4e016eae84 100644 --- a/ports/stm32/modbluetooth_hci.c +++ b/ports/stm32/modbluetooth_hci.c @@ -54,8 +54,13 @@ void mp_bluetooth_hci_poll_wrapper(uint32_t ticks_ms) { /******************************************************************************/ // HCI over IPCC +#include #include "rfcore.h" +STATIC uint16_t hci_uart_rx_buf_cur; +STATIC uint16_t hci_uart_rx_buf_len; +STATIC uint8_t hci_uart_rx_buf_data[256]; + int mp_bluetooth_hci_controller_deactivate(void) { return 0; } @@ -79,6 +84,8 @@ int mp_bluetooth_hci_uart_init(uint32_t port) { int mp_bluetooth_hci_uart_activate(void) { rfcore_ble_init(); + hci_uart_rx_buf_cur = 0; + hci_uart_rx_buf_len = 0; return 0; } @@ -94,6 +101,31 @@ int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { return 0; } +// Callback to copy data into local hci_uart_rx_buf_data buffer for subsequent use. +STATIC int mp_bluetooth_hci_uart_msg_cb(void *env, const uint8_t *buf, size_t len) { + (void)env; + if (hci_uart_rx_buf_len + len > MP_ARRAY_SIZE(hci_uart_rx_buf_data)) { + len = MP_ARRAY_SIZE(hci_uart_rx_buf_data) - hci_uart_rx_buf_len; + } + memcpy(hci_uart_rx_buf_data + hci_uart_rx_buf_len, buf, len); + hci_uart_rx_buf_len += len; + return 0; +} + +int mp_bluetooth_hci_uart_readchar(void) { + if (hci_uart_rx_buf_cur >= hci_uart_rx_buf_len) { + hci_uart_rx_buf_cur = 0; + hci_uart_rx_buf_len = 0; + rfcore_ble_check_msg(mp_bluetooth_hci_uart_msg_cb, NULL); + } + + if (hci_uart_rx_buf_cur < hci_uart_rx_buf_len) { + return hci_uart_rx_buf_data[hci_uart_rx_buf_cur++]; + } else { + return -1; + } +} + #else /******************************************************************************/ @@ -153,6 +185,16 @@ int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { return 0; } +// This function expects the controller to be in the wake state via a previous call +// to mp_bluetooth_hci_controller_woken. +int mp_bluetooth_hci_uart_readchar(void) { + if (uart_rx_any(&mp_bluetooth_hci_uart_obj)) { + return uart_rx_char(&mp_bluetooth_hci_uart_obj); + } else { + return -1; + } +} + #endif // defined(STM32WB) #endif // MICROPY_PY_BLUETOOTH diff --git a/ports/stm32/nimble.c b/ports/stm32/nimble.c index ff78a0a1a3..1f4aa4b2ce 100644 --- a/ports/stm32/nimble.c +++ b/ports/stm32/nimble.c @@ -67,28 +67,13 @@ void mp_bluetooth_nimble_port_start(void) { ble_hs_start(); } -#if defined(STM32WB) - -#include "rfcore.h" - -void mp_bluetooth_nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { - // Protect in case it's called from ble_npl_sem_pend at thread-level - MICROPY_PY_LWIP_ENTER - rfcore_ble_check_msg(rx_cb, rx_arg); - MICROPY_PY_LWIP_EXIT -} - -#else - -#include "uart.h" - void mp_bluetooth_nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { bool host_wake = mp_bluetooth_hci_controller_woken(); - while (uart_rx_any(&mp_bluetooth_hci_uart_obj)) { - uint8_t data = uart_rx_char(&mp_bluetooth_hci_uart_obj); + int chr; + while ((chr = mp_bluetooth_hci_uart_readchar()) >= 0) { //printf("UART RX: %02x\n", data); - rx_cb(rx_arg, data); + rx_cb(rx_arg, chr); } if (host_wake) { @@ -96,8 +81,6 @@ void mp_bluetooth_nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { } } -#endif // defined(STM32WB) - void mp_bluetooth_nimble_hci_uart_tx_strn(const char *str, uint len) { mp_bluetooth_hci_uart_write((const uint8_t *)str, len); } diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c index 8221527658..9b513839c8 100644 --- a/ports/stm32/rfcore.c +++ b/ports/stm32/rfcore.c @@ -56,7 +56,7 @@ typedef struct _tl_list_node_t { } tl_list_node_t; typedef struct _parse_hci_info_t { - int (*cb_fun)(void *, uint8_t); + int (*cb_fun)(void *, const uint8_t *, size_t); void *cb_env; bool was_hci_reset_evt; } parse_hci_info_t; @@ -190,9 +190,7 @@ STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { // Standard BT HCI ACL packet kind = "HCI_ACL"; if (parse != NULL) { - for (size_t i = 0; i < len; ++i) { - parse->cb_fun(parse->cb_env, buf[i]); - } + parse->cb_fun(parse->cb_env, buf, len); } break; } @@ -205,12 +203,11 @@ STATIC void tl_parse_hci_msg(const uint8_t *buf, parse_hci_info_t *parse) { len -= 1; fix = true; } - for (size_t i = 0; i < len; ++i) { - parse->cb_fun(parse->cb_env, buf[i]); - } + parse->cb_fun(parse->cb_env, buf, len); if (fix) { len += 1; - parse->cb_fun(parse->cb_env, 0x00); // success + uint8_t data = 0x00; // success + parse->cb_fun(parse->cb_env, &data, 1); } // Check for successful HCI_Reset event parse->was_hci_reset_evt = buf[1] == 0x0e && buf[2] == 0x04 && buf[3] == 0x01 @@ -403,7 +400,7 @@ void rfcore_ble_hci_cmd(size_t len, const uint8_t *src) { IPCC->C1SCR = ch << 16; } -void rfcore_ble_check_msg(int (*cb)(void *, uint8_t), void *env) { +void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env) { parse_hci_info_t parse = { cb, env, false }; tl_check_msg(&ipcc_mem_ble_evt_queue, IPCC_CH_BLE, &parse); diff --git a/ports/stm32/rfcore.h b/ports/stm32/rfcore.h index 8a04075732..138c438f12 100644 --- a/ports/stm32/rfcore.h +++ b/ports/stm32/rfcore.h @@ -32,6 +32,6 @@ void rfcore_init(void); void rfcore_ble_init(void); void rfcore_ble_hci_cmd(size_t len, const uint8_t *src); -void rfcore_ble_check_msg(int (*cb)(void *, uint8_t), void *env); +void rfcore_ble_check_msg(int (*cb)(void *, const uint8_t *, size_t), void *env); #endif // MICROPY_INCLUDED_STM32_RFCORE_H