diff --git a/ports/nrf/mpbthciport.c b/ports/nrf/mpbthciport.c index 60ce7f3b30..1795151f35 100644 --- a/ports/nrf/mpbthciport.c +++ b/ports/nrf/mpbthciport.c @@ -29,53 +29,92 @@ #include "py/runtime.h" #include "py/mperrno.h" #include "py/mphal.h" +#include "shared/runtime/softtimer.h" #if MICROPY_PY_BLUETOOTH #define DEBUG_printf(...) // mp_printf(&mp_plat_print, "mpbthciport.c: " __VA_ARGS__) #include "mpbthciport.h" -#include "drivers/ticker.h" +// #include "drivers/ticker.h" -#define BLUETOOTH_TICKER_SLOT 0 +// #define BLUETOOTH_TICKER_SLOT 0 + +// Soft timer and scheduling node for scheduling a HCI poll. +static soft_timer_entry_t mp_bluetooth_hci_soft_timer; +static mp_sched_node_t mp_bluetooth_hci_sched_node; + + +// This is called by soft_timer and executes at PendSV level. +static void mp_bluetooth_hci_soft_timer_callback(soft_timer_entry_t *self) { + mp_bluetooth_hci_poll_now(); +} // // Prevent double-enqueuing of the scheduled task. -static volatile bool events_task_is_scheduled = false; +// static volatile bool events_task_is_scheduled = false; void mp_bluetooth_hci_init(void) { /* Start regular background task to handle events */ - events_task_is_scheduled = false; - set_ticker_callback(BLUETOOTH_TICKER_SLOT, mp_bluetooth_hci_poll_now, 0); + // events_task_is_scheduled = false; + // set_ticker_callback(BLUETOOTH_TICKER_SLOT, mp_bluetooth_hci_poll_now, 0); + soft_timer_static_init( + &mp_bluetooth_hci_soft_timer, + SOFT_TIMER_MODE_ONE_SHOT, + 0, + mp_bluetooth_hci_soft_timer_callback + ); } void mp_bluetooth_hci_deinit(void) { - clear_ticker_callback(BLUETOOTH_TICKER_SLOT); - events_task_is_scheduled = false; + // clear_ticker_callback(BLUETOOTH_TICKER_SLOT); + // events_task_is_scheduled = false; + soft_timer_remove(&mp_bluetooth_hci_soft_timer); + +} + +// // For synchronous mode, we run all BLE stack code inside a scheduled task. +// // This task is scheduled periodically via a timer. +// static mp_obj_t run_events_scheduled_task(mp_obj_t none_in) { +// (void)none_in; +// events_task_is_scheduled = false; +// mp_bluetooth_hci_poll(); +// return mp_const_none; +// } +// static MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task); + + +// // Called periodically (ticker) to request that processing happens in the scheduler. +// int32_t mp_bluetooth_hci_poll_now(void) { +// // Return interval (128ms in 16us ticks) until next callback run +// uint32_t next_tick = 128000 / 16; +// 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 (5ms). +// next_tick = 5000 / 16; +// } +// } +// return next_tick; +// } + +// static void mp_bluetooth_hci_start_polling(void) { +// mp_bluetooth_hci_poll_now(); +// } + +void mp_bluetooth_hci_poll_in_ms(uint32_t ms) { + soft_timer_reinsert(&mp_bluetooth_hci_soft_timer, ms); } // For synchronous mode, we run all BLE stack code inside a scheduled task. -// This task is scheduled periodically via a timer. -static mp_obj_t run_events_scheduled_task(mp_obj_t none_in) { - (void)none_in; - events_task_is_scheduled = false; +static void run_events_scheduled_task(mp_sched_node_t *node) { + // This will process all buffered HCI UART data, and run any callouts or events. mp_bluetooth_hci_poll(); - return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(run_events_scheduled_task_obj, run_events_scheduled_task); - -// Called periodically (ticker) to request that processing happens in the scheduler. -int32_t mp_bluetooth_hci_poll_now(void) { - // Return interval (128ms in 16us ticks) until next callback run - uint32_t next_tick = 128000 / 16; - 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 (5ms). - next_tick = 5000 / 16; - } - } - return next_tick; +// 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_poll_now(void) { + mp_sched_schedule_node(&mp_bluetooth_hci_sched_node, run_events_scheduled_task); } #endif // MICROPY_PY_BLUETOOTH diff --git a/ports/nrf/mpbthciport.h b/ports/nrf/mpbthciport.h index 21bc395d46..4d0dda6aaa 100644 --- a/ports/nrf/mpbthciport.h +++ b/ports/nrf/mpbthciport.h @@ -30,8 +30,9 @@ void mp_bluetooth_hci_init(void); void mp_bluetooth_hci_deinit(void); -// Poll the HCI now. -int32_t mp_bluetooth_hci_poll_now(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 HCI data and pass to the stack, and run pending events/callouts. diff --git a/ports/nrf/mpnimbleport.c b/ports/nrf/mpnimbleport.c index 559519e728..4b0b8b42ca 100644 --- a/ports/nrf/mpnimbleport.c +++ b/ports/nrf/mpnimbleport.c @@ -61,10 +61,14 @@ void mp_bluetooth_hci_controller_init(void) { // Tell the host that we are ready to receive packets ble_ll_hci_send_noop(); + + // Start polling for date. + mp_bluetooth_hci_poll_now(); } void mp_bluetooth_hci_controller_deinit(void) { mp_bluetooth_hci_deinit(); + } // The global BLE controller LL data object @@ -92,6 +96,11 @@ void mp_bluetooth_hci_poll(void) { // Run any remaining events. 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. ----------------- @@ -123,6 +132,7 @@ static func nrf_ble_isr_rtc0 = NULL; void RADIO_IRQHandler(void) { if (nrf_ble_isr_phy != NULL) { nrf_ble_isr_phy(); + mp_bluetooth_hci_poll_in_ms(5); } }