Skip to content

Commit

Permalink
stm32: Provide a custom BTstack runloop that integrates with soft timer.
Browse files Browse the repository at this point in the history
It reschedules the BT HCI poll soft timer so that it is called exactly when
the next timer expires.

Signed-off-by: Damien George <damien@micropython.org>
  • Loading branch information
dpgeorge committed May 19, 2021
1 parent 3fa68b6 commit a012613
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 17 deletions.
1 change: 0 additions & 1 deletion extmod/btstack/btstack.mk
Expand Up @@ -30,7 +30,6 @@ INC += -I$(BTSTACK_DIR)/3rd-party/yxml
SRC_BTSTACK = \
$(addprefix lib/btstack/src/, $(SRC_FILES)) \
$(addprefix lib/btstack/src/ble/, $(filter-out %_tlv.c, $(SRC_BLE_FILES))) \
lib/btstack/platform/embedded/btstack_run_loop_embedded.c

ifeq ($(MICROPY_BLUETOOTH_BTSTACK_USB),1)
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_H4),1)
Expand Down
90 changes: 74 additions & 16 deletions ports/stm32/mpbtstackport.c
Expand Up @@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Damien P. George
* Copyright (c) 2020-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
Expand Down Expand Up @@ -31,30 +31,78 @@
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK

#include "lib/btstack/src/btstack.h"
#include "lib/btstack/platform/embedded/btstack_run_loop_embedded.h"
#include "lib/btstack/platform/embedded/hal_cpu.h"
#include "lib/btstack/platform/embedded/hal_time_ms.h"

#include "extmod/mpbthci.h"
#include "extmod/btstack/btstack_hci_uart.h"
#include "extmod/btstack/modbluetooth_btstack.h"

// The IRQ functionality in btstack_run_loop_embedded.c is not used, so the
// following three functions are empty.
void mp_bluetooth_hci_poll_in_ms(uint32_t ms);

static btstack_linked_list_t mp_btstack_runloop_timers;

static void mp_btstack_runloop_init(void) {
mp_btstack_runloop_timers = NULL;
}

void hal_cpu_disable_irqs(void) {
static void mp_btstack_runloop_set_timer(btstack_timer_source_t *tim, uint32_t timeout_ms) {
tim->timeout = mp_hal_ticks_ms() + timeout_ms + 1;
}

void hal_cpu_enable_irqs(void) {
static void mp_btstack_runloop_add_timer(btstack_timer_source_t *tim) {
btstack_linked_item_t **node = &mp_btstack_runloop_timers;
for (; *node; node = &(*node)->next) {
btstack_timer_source_t *node_tim = (btstack_timer_source_t *)*node;
if (node_tim == tim) {
// Timer is already in the list, don't add it.
return;
}
int32_t delta = btstack_time_delta(tim->timeout, node_tim->timeout);
if (delta < 0) {
// Found sorted location in list.
break;
}
}

// Insert timer into list in sorted location.
tim->item.next = *node;
*node = &tim->item;

// Reschedule the HCI poll if this timer is at the head of the list.
if (mp_btstack_runloop_timers == &tim->item) {
int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
mp_bluetooth_hci_poll_in_ms(delta_ms);
}
}

void hal_cpu_enable_irqs_and_sleep(void) {
static bool mp_btstack_runloop_remove_timer(btstack_timer_source_t *tim) {
return btstack_linked_list_remove(&mp_btstack_runloop_timers, (btstack_linked_item_t *)tim);
}

uint32_t hal_time_ms(void) {
static void mp_btstack_runloop_execute(void) {
// Should not be called.
}

static void mp_btstack_runloop_dump_timer(void) {
// Not implemented/needed.
}

static uint32_t mp_btstack_runloop_get_time_ms(void) {
return mp_hal_ticks_ms();
}

static const btstack_run_loop_t mp_btstack_runloop_stm32 = {
&mp_btstack_runloop_init,
NULL, // add_data_source,
NULL, // remove_data_source,
NULL, // enable_data_source_callbacks,
NULL, // disable_data_source_callbacks,
&mp_btstack_runloop_set_timer,
&mp_btstack_runloop_add_timer,
&mp_btstack_runloop_remove_timer,
&mp_btstack_runloop_execute,
&mp_btstack_runloop_dump_timer,
&mp_btstack_runloop_get_time_ms,
};

STATIC const hci_transport_config_uart_t hci_transport_config_uart = {
HCI_TRANSPORT_CONFIG_UART,
MICROPY_HW_BLE_UART_BAUDRATE,
Expand All @@ -68,22 +116,32 @@ void mp_bluetooth_hci_poll(void) {
return;
}

// Process uart data.
// Process UART data.
if (mp_bluetooth_btstack_state != MP_BLUETOOTH_BTSTACK_STATE_HALTING) {
mp_bluetooth_btstack_hci_uart_process();
}

// Call the BTstack run loop.
btstack_run_loop_embedded_execute_once();
// Process any BTstack timers.
while (mp_btstack_runloop_timers != NULL) {
btstack_timer_source_t *tim = (btstack_timer_source_t *)mp_btstack_runloop_timers;
int32_t delta_ms = btstack_time_delta(tim->timeout, mp_hal_ticks_ms());
if (delta_ms > 0) {
// Timer has not expired yet, reschedule HCI poll for this timer.
mp_bluetooth_hci_poll_in_ms(delta_ms);
break;
}
btstack_linked_list_pop(&mp_btstack_runloop_timers);
tim->process(tim);
}
}

void mp_bluetooth_btstack_port_init(void) {
static bool run_loop_init = false;
if (!run_loop_init) {
run_loop_init = true;
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
btstack_run_loop_init(&mp_btstack_runloop_stm32);
} else {
btstack_run_loop_embedded_get_instance()->init();
mp_btstack_runloop_stm32.init();
}

// hci_dump_open(NULL, HCI_DUMP_STDOUT);
Expand Down

0 comments on commit a012613

Please sign in to comment.