diff options
-rw-r--r-- | drivers/cyw43/cywbt.c | 100 | ||||
-rw-r--r-- | extmod/modbluetooth_hci.h (renamed from drivers/cyw43/cywbt.h) | 34 | ||||
-rw-r--r-- | extmod/nimble/hal/hal_uart.c (renamed from extmod/nimble/nimble/hci_uart.c) | 27 | ||||
-rw-r--r-- | extmod/nimble/hal/hal_uart.h | 1 | ||||
-rw-r--r-- | extmod/nimble/nimble.mk | 2 | ||||
-rw-r--r-- | extmod/nimble/nimble/nimble_hci_uart.h (renamed from extmod/nimble/nimble/hci_uart.h) | 23 | ||||
-rw-r--r-- | extmod/nimble/nimble/npl_os.c | 4 | ||||
-rw-r--r-- | ports/stm32/Makefile | 3 | ||||
-rw-r--r-- | ports/stm32/main.c | 8 | ||||
-rw-r--r-- | ports/stm32/modbluetooth_hci.c | 158 | ||||
-rw-r--r-- | ports/stm32/nimble.c | 59 | ||||
-rw-r--r-- | ports/stm32/nimble_hci_uart.c | 176 | ||||
-rw-r--r-- | ports/stm32/pendsv.h | 4 | ||||
-rw-r--r-- | ports/stm32/systick.h | 4 |
14 files changed, 338 insertions, 265 deletions
diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c index fae661608d..79318f4483 100644 --- a/drivers/cyw43/cywbt.c +++ b/drivers/cyw43/cywbt.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Damien P. George + * Copyright (c) 2019-2020 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,8 +31,7 @@ #include "py/mphal.h" #include "pin_static_af.h" #include "uart.h" -#include "cywbt.h" -#include "nimble/hci_uart.h" +#include "extmod/modbluetooth_hci.h" #if MICROPY_PY_NETWORK_CYW43 @@ -42,7 +41,7 @@ extern const char fw_4343WA1_7_45_98_50_start; /******************************************************************************/ // CYW BT HCI low-level driver -static void cywbt_wait_cts_low(void) { +STATIC void cywbt_wait_cts_low(void) { mp_hal_pin_config(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0); for (int i = 0; i < 200; ++i) { if (mp_hal_pin_read(pyb_pin_BT_CTS) == 0) { @@ -53,13 +52,13 @@ static void cywbt_wait_cts_low(void) { mp_hal_pin_config_alt_static(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, STATIC_AF_USART6_CTS); } -static int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { - uart_tx_strn(&bt_hci_uart_obj, (void*)buf, len); +STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { + uart_tx_strn(&mp_bluetooth_hci_uart_obj, (void*)buf, len); for (int i = 0; i < 6; ++i) { - while (!uart_rx_any(&bt_hci_uart_obj)) { + while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&bt_hci_uart_obj); + buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); } // expect a comand complete event (event 0x0e) @@ -76,17 +75,17 @@ static int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) { int sz = buf[2] - 3; for (int i = 0; i < sz; ++i) { - while (!uart_rx_any(&bt_hci_uart_obj)) { + while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) { MICROPY_EVENT_POLL_HOOK } - buf[i] = uart_rx_char(&bt_hci_uart_obj); + buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj); } return 0; } -static int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) { - uint8_t *buf = bt_hci_cmd_buf; +STATIC int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) { + uint8_t *buf = mp_bluetooth_hci_cmd_buf; buf[0] = 0x01; buf[1] = ocf; buf[2] = ogf << 2 | ocf >> 8; @@ -97,19 +96,19 @@ static int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *para return cywbt_hci_cmd_raw(4 + param_len, buf); } -static void put_le16(uint8_t *buf, uint16_t val) { +STATIC void put_le16(uint8_t *buf, uint16_t val) { buf[0] = val; buf[1] = val >> 8; } -static void put_le32(uint8_t *buf, uint32_t val) { +STATIC void put_le32(uint8_t *buf, uint32_t val) { buf[0] = val; buf[1] = val >> 8; buf[2] = val >> 16; buf[3] = val >> 24; } -static int cywbt_set_baudrate(uint32_t baudrate) { +STATIC int cywbt_set_baudrate(uint32_t baudrate) { uint8_t buf[6]; put_le16(buf, 0); put_le32(buf + 2, baudrate); @@ -117,12 +116,12 @@ static int cywbt_set_baudrate(uint32_t baudrate) { } // download firmware -static int cywbt_download_firmware(const uint8_t *firmware) { +STATIC int cywbt_download_firmware(const uint8_t *firmware) { cywbt_hci_cmd(0x3f, 0x2e, 0, NULL); bool last_packet = false; while (!last_packet) { - uint8_t *buf = bt_hci_cmd_buf; + uint8_t *buf = mp_bluetooth_hci_cmd_buf; memcpy(buf + 1, firmware, 3); firmware += 3; last_packet = buf[1] == 0x4e; @@ -149,15 +148,15 @@ static int cywbt_download_firmware(const uint8_t *firmware) { cywbt_wait_cts_low(); mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external) - nimble_hci_uart_set_baudrate(115200); + mp_bluetooth_hci_uart_set_baudrate(115200); cywbt_set_baudrate(3000000); - nimble_hci_uart_set_baudrate(3000000); + mp_bluetooth_hci_uart_set_baudrate(3000000); return 0; } -int cywbt_init(void) { - // This is called from Nimble via hal_uart_config which will have already initialized the UART. +int mp_bluetooth_hci_controller_init(void) { + // This is called immediately after the UART is initialised during stack initialisation. mp_hal_pin_output(pyb_pin_BT_REG_ON); mp_hal_pin_low(pyb_pin_BT_REG_ON); @@ -172,11 +171,11 @@ int cywbt_init(void) { return 0; } -int cywbt_activate(void) { +int mp_bluetooth_hci_controller_activate(void) { uint8_t buf[256]; mp_hal_pin_low(pyb_pin_BT_REG_ON); - nimble_hci_uart_set_baudrate(115200); + mp_bluetooth_hci_uart_set_baudrate(115200); mp_hal_delay_ms(100); mp_hal_pin_high(pyb_pin_BT_REG_ON); cywbt_wait_cts_low(); @@ -186,7 +185,7 @@ int cywbt_activate(void) { // Change baudrate cywbt_set_baudrate(3000000); - nimble_hci_uart_set_baudrate(3000000); + mp_bluetooth_hci_uart_set_baudrate(3000000); cywbt_download_firmware((const uint8_t*)CYWBT_FW_ADDR); @@ -220,4 +219,57 @@ int cywbt_activate(void) { return 0; } +int mp_bluetooth_hci_controller_deactivate(void) { + mp_hal_pin_low(pyb_pin_BT_REG_ON); + + return 0; +} + +#ifdef pyb_pin_BT_DEV_WAKE +STATIC uint32_t bt_sleep_ticks; +#endif + +int mp_bluetooth_hci_controller_sleep_maybe(void) { + #ifdef pyb_pin_BT_DEV_WAKE + if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { + if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { + mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep + } + } + #endif + return 0; +} + +bool mp_bluetooth_hci_controller_woken(void) { + #ifdef pyb_pin_BT_HOST_WAKE + bool host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); + /* + // this is just for info/tracing purposes + static bool last_host_wake = false; + if (host_wake != last_host_wake) { + printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake); + last_host_wake = host_wake; + } + */ + return host_wake; + #else + return true; + #endif +} + +int mp_bluetooth_hci_controller_wakeup(void) { + #ifdef pyb_pin_BT_DEV_WAKE + bt_sleep_ticks = mp_hal_ticks_ms(); + + if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { + mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up + // Use delay_us rather than delay_ms to prevent running the scheduler (which + // might result in more BLE operations). + mp_hal_delay_us(5000); // can't go lower than this + } + #endif + + return 0; +} + #endif diff --git a/drivers/cyw43/cywbt.h b/extmod/modbluetooth_hci.h index 9809d7f41a..6d44761a4e 100644 --- a/drivers/cyw43/cywbt.h +++ b/extmod/modbluetooth_hci.h @@ -23,13 +23,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_DRIVERS_CYW43_CYWBT_H -#define MICROPY_INCLUDED_DRIVERS_CYW43_CYWBT_H -extern uint8_t bt_hci_cmd_buf[4 + 256]; -extern pyb_uart_obj_t bt_hci_uart_obj; +#ifndef MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_HCI_H +#define MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_HCI_H -int cywbt_init(void); -int cywbt_activate(void); +#include "uart.h" -#endif // MICROPY_INCLUDED_DRIVERS_CYW43_CYWBT_H +// Optionally can be implemented by the driver. +int mp_bluetooth_hci_controller_init(void); +int mp_bluetooth_hci_controller_activate(void); +int mp_bluetooth_hci_controller_deactivate(void); + +// Tell the controller to go to sleep (e.g. on RX if we don't think we're expecting anything more). +int mp_bluetooth_hci_controller_sleep_maybe(void); +// True if the controller woke us up. +bool mp_bluetooth_hci_controller_woken(void); +// Wake up the controller (e.g. we're about to TX). +int mp_bluetooth_hci_controller_wakeup(void); + +// Storage and bindings that need to be implemented by the port. +// These are used by the stack bindings (e.g. nimble/hal_uart.c) +// as well as potentially the driver (e.g. cywbt.c). +extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; +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_write(const uint8_t *buf, size_t len); + +#endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_HCI_H diff --git a/extmod/nimble/nimble/hci_uart.c b/extmod/nimble/hal/hal_uart.c index b4ac4e7388..fba82b8304 100644 --- a/extmod/nimble/nimble/hci_uart.c +++ b/extmod/nimble/hal/hal_uart.c @@ -28,14 +28,11 @@ #include "py/mphal.h" #include "pin_static_af.h" #include "nimble/ble.h" -#include "hal/hal_uart.h" -#include "hci_uart.h" +#include "extmod/nimble/hal/hal_uart.h" +#include "extmod/modbluetooth_hci.h" +#include "extmod/nimble/nimble/nimble_hci_uart.h" -#if MICROPY_BLUETOOTH_NIMBLE - -/******************************************************************************/ -// Bindings Uart to Nimble -uint8_t bt_hci_cmd_buf[4 + 256]; +#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE static hal_uart_tx_cb_t hal_uart_tx_cb; static void *hal_uart_tx_arg; @@ -51,9 +48,9 @@ int hal_uart_init_cbs(uint32_t port, hal_uart_tx_cb_t tx_cb, void *tx_arg, hal_u } int hal_uart_config(uint32_t port, uint32_t baudrate, uint32_t bits, uint32_t stop, uint32_t parity, uint32_t flow) { - nimble_hci_uart_configure(port); - nimble_hci_uart_set_baudrate(baudrate); - return nimble_hci_uart_activate(); + mp_bluetooth_hci_uart_init(port); + mp_bluetooth_hci_uart_set_baudrate(baudrate); + return mp_bluetooth_hci_uart_activate(); } void hal_uart_start_tx(uint32_t port) { @@ -63,7 +60,7 @@ void hal_uart_start_tx(uint32_t port) { if (data == -1) { break; } - bt_hci_cmd_buf[len++] = data; + mp_bluetooth_hci_cmd_buf[len++] = data; } #if 0 @@ -74,15 +71,15 @@ void hal_uart_start_tx(uint32_t port) { printf("\n"); #endif - nimble_hci_uart_tx_strn((void*)bt_hci_cmd_buf, len); + mp_bluetooth_nimble_hci_uart_tx_strn((void*)mp_bluetooth_hci_cmd_buf, len); } int hal_uart_close(uint32_t port) { return 0; // success } -void nimble_uart_process(void) { - nimble_hci_uart_rx(hal_uart_rx_cb, hal_uart_rx_arg); +void mp_bluetooth_nimble_hci_uart_process(void) { + mp_bluetooth_nimble_hci_uart_rx(hal_uart_rx_cb, hal_uart_rx_arg); } -#endif // MICROPY_BLUETOOTH_NIMBLE +#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/extmod/nimble/hal/hal_uart.h b/extmod/nimble/hal/hal_uart.h index 294dfb50dd..0ef04bc81e 100644 --- a/extmod/nimble/hal/hal_uart.h +++ b/extmod/nimble/hal/hal_uart.h @@ -10,6 +10,7 @@ typedef int (*hal_uart_tx_cb_t)(void *arg); typedef int (*hal_uart_rx_cb_t)(void *arg, uint8_t data); +// Called by NimBLE, implemented in hal_uart.c. 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); int hal_uart_config(uint32_t port, uint32_t baud, uint32_t bits, uint32_t stop, uint32_t parity, uint32_t flow); void hal_uart_start_tx(uint32_t port); diff --git a/extmod/nimble/nimble.mk b/extmod/nimble/nimble.mk index 4d2c6637a4..60dbe60b0a 100644 --- a/extmod/nimble/nimble.mk +++ b/extmod/nimble/nimble.mk @@ -84,7 +84,7 @@ SRC_LIB += $(addprefix $(NIMBLE_LIB_DIR)/, \ EXTMOD_SRC_C += $(addprefix $(NIMBLE_EXTMOD_DIR)/, \ nimble/npl_os.c \ - nimble/hci_uart.c \ + hal/hal_uart.c \ ) INC += -I$(TOP)/$(NIMBLE_EXTMOD_DIR) diff --git a/extmod/nimble/nimble/hci_uart.h b/extmod/nimble/nimble/nimble_hci_uart.h index 3d4a2a9835..646a12dac1 100644 --- a/extmod/nimble/nimble/hci_uart.h +++ b/extmod/nimble/nimble/nimble_hci_uart.h @@ -23,21 +23,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H -#define MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H +#ifndef MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_NIMBLE_HCI_UART_H +#define MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_NIMBLE_HCI_UART_H -#include "extmod/nimble/hal/hal_uart.h" - -// To be implemented by the port. +// Extensions to extmod/modbluetooth_hci.h specific to NimBLE. -int nimble_hci_uart_configure(uint32_t port); - -// This will default to MICROPY_HW_BLE_UART_BAUDRATE, but can be updated later. -int nimble_hci_uart_set_baudrate(uint32_t baudrate); +#include "extmod/nimble/hal/hal_uart.h" -int nimble_hci_uart_activate(void); +// Helpers called from ports. +void mp_bluetooth_nimble_hci_uart_process(void); -void nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg); -void nimble_hci_uart_tx_strn(const char *str, uint len); +// Must be provided by the port. +void mp_bluetooth_nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg); +void mp_bluetooth_nimble_hci_uart_tx_strn(const char *str, uint len); -#endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_HCI_UART_H +#endif // MICROPY_INCLUDED_EXTMOD_NIMBLE_NIMBLE_NIMBLE_HCI_UART_H diff --git a/extmod/nimble/nimble/npl_os.c b/extmod/nimble/nimble/npl_os.c index 4875d2d1ad..57ab689e6b 100644 --- a/extmod/nimble/nimble/npl_os.c +++ b/extmod/nimble/nimble/npl_os.c @@ -29,6 +29,7 @@ #include "py/runtime.h" #include "nimble/ble.h" #include "nimble/nimble_npl.h" +#include "nimble/nimble_hci_uart.h" #define DEBUG_OS_printf(...) //printf(__VA_ARGS__) #define DEBUG_MALLOC_printf(...) //printf(__VA_ARGS__) @@ -234,8 +235,7 @@ 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) { - extern void nimble_uart_process(void); - nimble_uart_process(); + mp_bluetooth_nimble_hci_uart_process(); if (sem->count != 0) { break; } diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 235b251644..fab2f621b2 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -460,10 +460,11 @@ endif ifeq ($(MICROPY_PY_BLUETOOTH),1) +SRC_C += modbluetooth_hci.c + ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1) include $(TOP)/extmod/nimble/nimble.mk SRC_C += nimble.c -SRC_C += nimble_hci_uart.c endif ifeq ($(MICROPY_PY_NETWORK_CYW43),1) diff --git a/ports/stm32/main.c b/ports/stm32/main.c index e221df0d0f..78973f4118 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -49,7 +49,7 @@ #include "drivers/cyw43/cyw43.h" #endif -#if MICROPY_BLUETOOTH_NIMBLE +#if MICROPY_PY_BLUETOOTH #include "extmod/modbluetooth.h" #endif @@ -539,9 +539,9 @@ void stm32_main(uint32_t reset_mode) { #endif systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper); #endif - #if MICROPY_BLUETOOTH_NIMBLE - extern void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms); - systick_enable_dispatch(SYSTICK_DISPATCH_NIMBLE, mod_bluetooth_nimble_poll_wrapper); + #if MICROPY_PY_BLUETOOTH + extern void mp_bluetooth_hci_poll_wrapper(uint32_t ticks_ms); + systick_enable_dispatch(SYSTICK_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll_wrapper); #endif #if MICROPY_PY_NETWORK_CYW43 diff --git a/ports/stm32/modbluetooth_hci.c b/ports/stm32/modbluetooth_hci.c new file mode 100644 index 0000000000..c6937b2b2a --- /dev/null +++ b/ports/stm32/modbluetooth_hci.c @@ -0,0 +1,158 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2020 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mphal.h" +#include "extmod/modbluetooth_hci.h" +#include "systick.h" +#include "pendsv.h" + +#include "py/obj.h" + +#if MICROPY_PY_BLUETOOTH + +uint8_t mp_bluetooth_hci_cmd_buf[4 + 256]; + +// Must be provided by the stack bindings. +extern void mp_bluetooth_hci_poll(void); + +// Hook for pendsv poller to run this periodically every 128ms +#define BLUETOOTH_HCI_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) + +// Called periodically (systick) or directly (e.g. uart irq). +void mp_bluetooth_hci_poll_wrapper(uint32_t ticks_ms) { + if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll); + } +} + +#if defined(STM32WB) + +/******************************************************************************/ +// HCI over IPCC + +#include "rfcore.h" + +int mp_bluetooth_hci_controller_deactivate(void) { + return 0; +} + +int mp_bluetooth_hci_controller_sleep_maybe(void) { + return 0; +} + +bool mp_bluetooth_hci_controller_woken(void) { + return true; +} + +int mp_bluetooth_hci_controller_wakeup(void) { + return 0; +} + +int mp_bluetooth_hci_uart_init(uint32_t port) { + (void)port; + return 0; +} + +int mp_bluetooth_hci_uart_activate(void) { + rfcore_ble_init(); + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + (void)baudrate; + return 0; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + MICROPY_PY_BLUETOOTH_ENTER + rfcore_ble_hci_cmd(len, (const uint8_t *)buf); + MICROPY_PY_BLUETOOTH_EXIT + return 0; +} + +#else + +/******************************************************************************/ +// HCI over UART + +#include "pendsv.h" +#include "uart.h" + +pyb_uart_obj_t mp_bluetooth_hci_uart_obj; + +static uint8_t hci_uart_rxbuf[512]; + +mp_obj_t mp_uart_interrupt(mp_obj_t self_in) { + // New HCI data, schedule mp_bluetooth_hci_poll to make the stack handle it. + mp_bluetooth_hci_poll_wrapper(0); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt); + +int mp_bluetooth_hci_uart_init(uint32_t port) { + // bits (8), stop (1), parity (none) and flow (rts/cts) are assumed to match MYNEWT_VAL_BLE_HCI_UART_ constants in syscfg.h. + mp_bluetooth_hci_uart_obj.base.type = &pyb_uart_type; + mp_bluetooth_hci_uart_obj.uart_id = port; + mp_bluetooth_hci_uart_obj.is_static = true; + mp_bluetooth_hci_uart_obj.timeout = 2; + mp_bluetooth_hci_uart_obj.timeout_char = 2; + MP_STATE_PORT(pyb_uart_obj_all)[mp_bluetooth_hci_uart_obj.uart_id - 1] = &mp_bluetooth_hci_uart_obj; + return 0; +} + +int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate) { + uart_init(&mp_bluetooth_hci_uart_obj, baudrate, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); + uart_set_rxbuf(&mp_bluetooth_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); + return 0; +} + +int mp_bluetooth_hci_uart_activate(void) { + // Interrupt on RX chunk received (idle) + // Trigger stack poll when this happens + mp_obj_t uart_irq_fn = mp_load_attr(MP_OBJ_FROM_PTR(&mp_bluetooth_hci_uart_obj), MP_QSTR_irq); + mp_obj_t uargs[] = { + MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj), + MP_OBJ_NEW_SMALL_INT(UART_FLAG_IDLE), + mp_const_true, + }; + mp_call_function_n_kw(uart_irq_fn, 3, 0, uargs); + + mp_bluetooth_hci_controller_init(); + mp_bluetooth_hci_controller_activate(); + + return 0; +} + +int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len) { + mp_bluetooth_hci_controller_wakeup(); + uart_tx_strn(&mp_bluetooth_hci_uart_obj, (void *)buf, len); + return 0; +} + +#endif // defined(STM32WB) + +#endif // MICROPY_PY_BLUETOOTH diff --git a/ports/stm32/nimble.c b/ports/stm32/nimble.c index b21b2bede7..ff78a0a1a3 100644 --- a/ports/stm32/nimble.c +++ b/ports/stm32/nimble.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2019 Jim Mussared + * Copyright (c) 2020 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,37 +31,26 @@ #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE -#include "systick.h" -#include "pendsv.h" - #include "transport/uart/ble_hci_uart.h" #include "host/ble_hs.h" +#include "extmod/modbluetooth_hci.h" #include "extmod/nimble/modbluetooth_nimble.h" +#include "extmod/nimble/nimble/nimble_hci_uart.h" -extern void nimble_uart_process(void); extern void os_eventq_run_all(void); extern void os_callout_process(void); -// Hook for pendsv poller to run this periodically every 128ms -#define NIMBLE_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0) - -void nimble_poll(void) { +void mp_bluetooth_hci_poll(void) { if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) { return; } - nimble_uart_process(); + mp_bluetooth_nimble_hci_uart_process(); os_callout_process(); os_eventq_run_all(); } -void mod_bluetooth_nimble_poll_wrapper(uint32_t ticks_ms) { - if (NIMBLE_TICK(ticks_ms)) { - pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); - } -} - void mp_bluetooth_nimble_port_preinit(void) { MP_STATE_PORT(bluetooth_nimble_memory) = NULL; ble_hci_uart_init(); @@ -70,13 +60,46 @@ void mp_bluetooth_nimble_port_postinit(void) { } void mp_bluetooth_nimble_port_deinit(void) { - #ifdef pyb_pin_BT_REG_ON - mp_hal_pin_low(pyb_pin_BT_REG_ON); - #endif + mp_bluetooth_hci_controller_deactivate(); } 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); + //printf("UART RX: %02x\n", data); + rx_cb(rx_arg, data); + } + + if (host_wake) { + mp_bluetooth_hci_controller_sleep_maybe(); + } +} + +#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); +} + #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/stm32/nimble_hci_uart.c b/ports/stm32/nimble_hci_uart.c deleted file mode 100644 index 1160855878..0000000000 --- a/ports/stm32/nimble_hci_uart.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018-2019 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/runtime.h" -#include "py/mphal.h" -#include "extmod/nimble/nimble/hci_uart.h" - -#if MICROPY_BLUETOOTH_NIMBLE - -#if defined(STM32WB) - -/******************************************************************************/ -// HCI over IPCC - -#include "rfcore.h" - -int nimble_hci_uart_configure(uint32_t port) { - (void)port; - return 0; -} - -int nimble_hci_uart_set_baudrate(uint32_t baudrate) { - (void)baudrate; - return 0; -} - -int nimble_hci_uart_activate(void) { - rfcore_ble_init(); - return 0; -} - -void 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 -} - -void nimble_hci_uart_tx_strn(const char *str, uint len) { - MICROPY_PY_LWIP_ENTER - rfcore_ble_hci_cmd(len, (const uint8_t *)str); - MICROPY_PY_LWIP_EXIT -} - -#else - -/******************************************************************************/ -// HCI over UART - -#include "pendsv.h" -#include "uart.h" -#include "drivers/cyw43/cywbt.h" - -pyb_uart_obj_t bt_hci_uart_obj; -static uint8_t hci_uart_rxbuf[512]; - -#ifdef pyb_pin_BT_DEV_WAKE -static uint32_t bt_sleep_ticks; -#endif - -extern void nimble_poll(void); - -mp_obj_t mp_uart_interrupt(mp_obj_t self_in) { - pendsv_schedule_dispatch(PENDSV_DISPATCH_NIMBLE, nimble_poll); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt); - -int nimble_hci_uart_set_baudrate(uint32_t baudrate) { - uart_init(&bt_hci_uart_obj, baudrate, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, UART_HWCONTROL_RTS | UART_HWCONTROL_CTS); - uart_set_rxbuf(&bt_hci_uart_obj, sizeof(hci_uart_rxbuf), hci_uart_rxbuf); - return 0; -} - -int nimble_hci_uart_configure(uint32_t port) { - // bits (8), stop (1), parity (none) and flow (rts/cts) are assumed to match MYNEWT_VAL_BLE_HCI_UART_ constants in syscfg.h. - bt_hci_uart_obj.base.type = &pyb_uart_type; - bt_hci_uart_obj.uart_id = port; - bt_hci_uart_obj.is_static = true; - bt_hci_uart_obj.timeout = 2; - bt_hci_uart_obj.timeout_char = 2; - MP_STATE_PORT(pyb_uart_obj_all)[bt_hci_uart_obj.uart_id - 1] = &bt_hci_uart_obj; - return 0; -} - -int nimble_hci_uart_activate(void) { - // Interrupt on RX chunk received (idle) - // Trigger nimble poll when this happens - mp_obj_t uart_irq_fn = mp_load_attr(MP_OBJ_FROM_PTR(&bt_hci_uart_obj), MP_QSTR_irq); - mp_obj_t uargs[] = { - MP_OBJ_FROM_PTR(&mp_uart_interrupt_obj), - MP_OBJ_NEW_SMALL_INT(UART_FLAG_IDLE), - mp_const_true, - }; - mp_call_function_n_kw(uart_irq_fn, 3, 0, uargs); - - #if MICROPY_PY_NETWORK_CYW43 - cywbt_init(); - cywbt_activate(); - #endif - - return 0; -} - -void nimble_hci_uart_rx(hal_uart_rx_cb_t rx_cb, void *rx_arg) { - #ifdef pyb_pin_BT_HOST_WAKE - int host_wake = 0; - host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE); - /* - // this is just for info/tracing purposes - static int last_host_wake = 0; - if (host_wake != last_host_wake) { - printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake); - last_host_wake = host_wake; - } - */ - #endif - - while (uart_rx_any(&bt_hci_uart_obj)) { - uint8_t data = uart_rx_char(&bt_hci_uart_obj); - //printf("UART RX: %02x\n", data); - rx_cb(rx_arg, data); - } - - #ifdef pyb_pin_BT_DEV_WAKE - if (host_wake == 1 && mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) { - if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) { - //printf("BT SLEEP\n"); - mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep - } - } - #endif -} - -void nimble_hci_uart_tx_strn(const char *str, uint len) { - #ifdef pyb_pin_BT_DEV_WAKE - bt_sleep_ticks = mp_hal_ticks_ms(); - - if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) { - //printf("BT WAKE for TX\n"); - mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up - // Use delay_us rather than delay_ms to prevent running the scheduler (which - // might result in more BLE operations). - mp_hal_delay_us(5000); // can't go lower than this - } - #endif - - uart_tx_strn(&bt_hci_uart_obj, str, len); -} - -#endif // defined(STM32WB) - -#endif // MICROPY_BLUETOOTH_NIMBLE diff --git a/ports/stm32/pendsv.h b/ports/stm32/pendsv.h index dd3f8f2cb3..585f81e8bd 100644 --- a/ports/stm32/pendsv.h +++ b/ports/stm32/pendsv.h @@ -34,8 +34,8 @@ enum { PENDSV_DISPATCH_CYW43, #endif #endif - #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE - PENDSV_DISPATCH_NIMBLE, + #if MICROPY_PY_BLUETOOTH + PENDSV_DISPATCH_BLUETOOTH_HCI, #endif PENDSV_DISPATCH_MAX }; diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h index a70f03e176..6aef3f2e4e 100644 --- a/ports/stm32/systick.h +++ b/ports/stm32/systick.h @@ -37,8 +37,8 @@ enum { #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP SYSTICK_DISPATCH_LWIP, #endif - #if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE - SYSTICK_DISPATCH_NIMBLE, + #if MICROPY_PY_BLUETOOTH + SYSTICK_DISPATCH_BLUETOOTH_HCI, #endif SYSTICK_DISPATCH_MAX }; |