summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/main.c4
-rw-r--r--ports/stm32/mpbthciport.c85
-rw-r--r--ports/stm32/mpbthciport.h42
-rw-r--r--ports/stm32/mpbtstackport.c5
-rw-r--r--ports/stm32/mpnimbleport.c7
-rw-r--r--ports/stm32/rfcore.c4
-rw-r--r--ports/stm32/systick.h3
7 files changed, 111 insertions, 39 deletions
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index ca80daaceb..c8de2fd868 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -54,6 +54,7 @@
#endif
#include "boardctrl.h"
+#include "mpbthciport.h"
#include "mpu.h"
#include "rfcore.h"
#include "systick.h"
@@ -440,8 +441,7 @@ void stm32_main(uint32_t reset_mode) {
systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
#endif
#if MICROPY_PY_BLUETOOTH
- extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
- systick_enable_dispatch(SYSTICK_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_systick);
+ mp_bluetooth_hci_init();
#endif
#if MICROPY_PY_NETWORK_CYW43
diff --git a/ports/stm32/mpbthciport.c b/ports/stm32/mpbthciport.c
index c3cd864e2b..accb913e1f 100644
--- a/ports/stm32/mpbthciport.c
+++ b/ports/stm32/mpbthciport.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2018-2020 Damien P. George
+ * Copyright (c) 2018-2021 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
@@ -28,7 +28,8 @@
#include "py/mphal.h"
#include "extmod/mpbthci.h"
#include "extmod/modbluetooth.h"
-#include "systick.h"
+#include "mpbthciport.h"
+#include "softtimer.h"
#include "pendsv.h"
#include "lib/utils/mpirq.h"
@@ -38,22 +39,48 @@
uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
-// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
-// Request new data from the uart and pass to the stack, and run pending events/callouts.
-extern void mp_bluetooth_hci_poll(void);
+// Soft timer for scheduling a HCI poll.
+STATIC soft_timer_entry_t mp_bluetooth_hci_soft_timer;
-// Hook for pendsv poller to run this periodically every 128ms
-#define BLUETOOTH_HCI_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
+#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
+// Prevent double-enqueuing of the scheduled task.
+STATIC volatile bool events_task_is_scheduled;
+#endif
+
+// This is called by soft_timer and executes at IRQ_PRI_PENDSV.
+STATIC void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) {
+ mp_bluetooth_hci_poll_now();
+}
+
+void mp_bluetooth_hci_init(void) {
+ #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
+ events_task_is_scheduled = false;
+ #endif
+ soft_timer_static_init(
+ &mp_bluetooth_hci_soft_timer,
+ SOFT_TIMER_MODE_ONE_SHOT,
+ 0,
+ mp_bluetooth_hci_soft_timer_callback
+ );
+}
+
+STATIC void mp_bluetooth_hci_start_polling(void) {
+ #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
+ events_task_is_scheduled = false;
+ #endif
+ mp_bluetooth_hci_poll_now();
+}
+
+void mp_bluetooth_hci_poll_in_ms(uint32_t ms) {
+ soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms);
+}
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
// For synchronous mode, we run all BLE stack code inside a scheduled task.
-// This task is scheduled periodically (every 128ms) via SysTick, or
+// This task is scheduled periodically via a soft timer, or
// immediately on HCI UART RXIDLE.
-// Prevent double-enqueuing of the scheduled task.
-STATIC volatile bool events_task_is_scheduled = false;
-
STATIC mp_obj_t run_events_scheduled_task(mp_obj_t none_in) {
(void)none_in;
events_task_is_scheduled = false;
@@ -65,23 +92,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_sched
// Called periodically (systick) or directly (e.g. UART RX IRQ) in order to
// request that processing happens ASAP in the scheduler.
-void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
- if (events_task_is_scheduled) {
- return;
- }
-
- if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
+void mp_bluetooth_hci_poll_now(void) {
+ if (!events_task_is_scheduled) {
events_task_is_scheduled = mp_sched_schedule(MP_OBJ_FROM_PTR(&run_events_scheduled_task_obj), mp_const_none);
+ if (!events_task_is_scheduled) {
+ // The schedule queue is full, set callback to try again soon.
+ mp_bluetooth_hci_poll_in_ms(5);
+ }
}
}
#else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
-// Called periodically (systick) or directly (e.g. uart irq).
-void mp_bluetooth_hci_systick(uint32_t ticks_ms) {
- if (ticks_ms == 0 || BLUETOOTH_HCI_TICK(ticks_ms)) {
- pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
- }
+void mp_bluetooth_hci_poll_now(void) {
+ pendsv_schedule_dispatch(PENDSV_DISPATCH_BLUETOOTH_HCI, mp_bluetooth_hci_poll);
}
#endif
@@ -104,14 +128,13 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
DEBUG_printf("mp_bluetooth_hci_uart_init (stm32 rfcore)\n");
- #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
- events_task_is_scheduled = false;
- #endif
-
rfcore_ble_init();
hci_uart_rx_buf_cur = 0;
hci_uart_rx_buf_len = 0;
+ // Start the HCI polling to process any initial events/packets.
+ mp_bluetooth_hci_start_polling();
+
return 0;
}
@@ -163,7 +186,6 @@ int mp_bluetooth_hci_uart_readchar(void) {
/******************************************************************************/
// HCI over UART
-#include "pendsv.h"
#include "uart.h"
pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
@@ -173,7 +195,7 @@ static uint8_t hci_uart_rxbuf[768];
mp_obj_t mp_uart_interrupt(mp_obj_t self_in) {
// Queue up the scheduler to run the HCI UART and event processing ASAP.
- mp_bluetooth_hci_systick(0);
+ mp_bluetooth_hci_poll_now();
return mp_const_none;
}
@@ -182,10 +204,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_uart_interrupt_obj, mp_uart_interrupt);
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
DEBUG_printf("mp_bluetooth_hci_uart_init (stm32)\n");
- #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
- events_task_is_scheduled = false;
- #endif
-
// 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;
@@ -208,6 +226,9 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) {
mp_bluetooth_hci_uart_irq_obj.ishard = true;
uart_irq_config(&mp_bluetooth_hci_uart_obj, true);
+ // Start the HCI polling to process any initial events/packets.
+ mp_bluetooth_hci_start_polling();
+
return 0;
}
diff --git a/ports/stm32/mpbthciport.h b/ports/stm32/mpbthciport.h
new file mode 100644
index 0000000000..77919ee0e6
--- /dev/null
+++ b/ports/stm32/mpbthciport.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 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.
+ */
+#ifndef MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
+#define MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
+
+// Initialise the HCI subsystem (should be called once, early on).
+void mp_bluetooth_hci_init(void);
+
+// Poll the HCI now, or after a certain timeout.
+void mp_bluetooth_hci_poll_now(void);
+void mp_bluetooth_hci_poll_in_ms(uint32_t ms);
+
+// Must be provided by the stack bindings (e.g. mpnimbleport.c or mpbtstackport.c).
+// Request new data from the uart and pass to the stack, and run pending events/callouts.
+// This is a low-level function and should not be called directly, use
+// mp_bluetooth_hci_poll_now/mp_bluetooth_hci_poll_in_ms instead.
+void mp_bluetooth_hci_poll(void);
+
+#endif // MICROPY_INCLUDED_STM32_MPBTHCIPORT_H
diff --git a/ports/stm32/mpbtstackport.c b/ports/stm32/mpbtstackport.c
index 3dfd8cb3c4..abe4f6d3e2 100644
--- a/ports/stm32/mpbtstackport.c
+++ b/ports/stm32/mpbtstackport.c
@@ -38,6 +38,7 @@
#include "extmod/mpbthci.h"
#include "extmod/btstack/btstack_hci_uart.h"
#include "extmod/btstack/modbluetooth_btstack.h"
+#include "mpbthciport.h"
// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
// following three functions are empty.
@@ -75,6 +76,10 @@ void mp_bluetooth_hci_poll(void) {
// Call the BTstack run loop.
btstack_run_loop_embedded_execute_once();
+
+ // Call this function again in 128ms to check for new events.
+ // TODO: improve this by only calling back when needed.
+ mp_bluetooth_hci_poll_in_ms(128);
}
void mp_bluetooth_btstack_port_init(void) {
diff --git a/ports/stm32/mpnimbleport.c b/ports/stm32/mpnimbleport.c
index 0ba76fb277..e2d39e271c 100644
--- a/ports/stm32/mpnimbleport.c
+++ b/ports/stm32/mpnimbleport.c
@@ -40,6 +40,7 @@
#include "extmod/modbluetooth.h"
#include "extmod/nimble/modbluetooth_nimble.h"
#include "extmod/nimble/hal/hal_uart.h"
+#include "mpbthciport.h"
// Get any pending data from the UART and send it to NimBLE's HCI buffers.
// Any further processing by NimBLE will be run via its event queue.
@@ -56,6 +57,12 @@ void mp_bluetooth_hci_poll(void) {
// Run any remaining events (e.g. if there was no UART data).
mp_bluetooth_nimble_os_eventq_run_all();
}
+
+ if (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
+ // Call this function again in 128ms to check for new events.
+ // TODO: improve this by only calling back when needed.
+ mp_bluetooth_hci_poll_in_ms(128);
+ }
}
// --- Port-specific helpers for the generic NimBLE bindings. -----------------
diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c
index 049f6bdc10..67b63679a7 100644
--- a/ports/stm32/rfcore.c
+++ b/ports/stm32/rfcore.c
@@ -32,6 +32,7 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "extmod/modbluetooth.h"
+#include "mpbthciport.h"
#include "rtc.h"
#include "rfcore.h"
@@ -714,8 +715,7 @@ void IPCC_C1_RX_IRQHandler(void) {
#if MICROPY_PY_BLUETOOTH
// Queue up the scheduler to process UART data and run events.
- extern void mp_bluetooth_hci_systick(uint32_t ticks_ms);
- mp_bluetooth_hci_systick(0);
+ mp_bluetooth_hci_poll_now();
#endif
}
diff --git a/ports/stm32/systick.h b/ports/stm32/systick.h
index 6aef3f2e4e..6a05a4990a 100644
--- a/ports/stm32/systick.h
+++ b/ports/stm32/systick.h
@@ -37,9 +37,6 @@ enum {
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
SYSTICK_DISPATCH_LWIP,
#endif
- #if MICROPY_PY_BLUETOOTH
- SYSTICK_DISPATCH_BLUETOOTH_HCI,
- #endif
SYSTICK_DISPATCH_MAX
};