Skip to content

Commit

Permalink
drv/bluetooth_stm32_cc2640: fix ble observe
Browse files Browse the repository at this point in the history
The Bluetooth chip on the City and Technic hubs will stop receiving
advertisements after a while when observing. It isn't clear why this
is happening, but it seems to that there is a bug in the Bluetooth
chip firmware that causes it to start filtering out advertisements
from an individual advertiser after a while (i.e. it can still be
receiving advertisements from one device but stops receiving them
from another). Eventually it will stop receiving advertisements from
all devices.

To work around this, we restart the observation process every 10
seconds. In testing, we were never able to trigger the bug in less than
25 seconds or so. Therefore, 10 seconds should be more than enough to
ensure that we never miss an advertisement.

Fixes: pybricks/support#1096
  • Loading branch information
dlech committed Nov 26, 2023
1 parent fcf61e6 commit 4158c77
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

# Changelog

## [Unreleased]

### Fixes
- Fix observing stopping on City and Technic hubs after some time ([support#1096]).

[support#1096]: https://github.com/pybricks/support/issues/1096

## [3.3.0] - 2023-11-24

### Changed
Expand Down
31 changes: 30 additions & 1 deletion lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ static pbdrv_bluetooth_receive_handler_t receive_handler;
static pbdrv_bluetooth_receive_handler_t notification_handler;
static const pbdrv_bluetooth_stm32_cc2640_platform_data_t *pdata = &pbdrv_bluetooth_stm32_cc2640_platform_data;

// HACK: restart observing every 10 seconds to work around a bug in the Bluetooth
// chip firmware that causes it to stop receiving advertisements after a while.
#define OBSERVE_RESTART_INTERVAL 10000
static struct etimer observe_restart_timer;
static bool observe_restart_enabled;

/**
* Converts a ble error code to the most appropriate pbio error code.
* @param [in] status The ble error code.
Expand Down Expand Up @@ -476,6 +482,8 @@ static PT_THREAD(scan_and_connect_task(struct pt *pt, pbio_task_t *task)) {

// temporarily stop observing so we can active scan
if (is_observing) {
observe_restart_enabled = false;

PT_WAIT_WHILE(pt, write_xfer_size);
GAP_DeviceDiscoveryCancel();
PT_WAIT_UNTIL(pt, hci_command_status);
Expand Down Expand Up @@ -716,6 +724,11 @@ static PT_THREAD(scan_and_connect_task(struct pt *pt, pbio_task_t *task)) {
}

device_discovery_done = false;

PROCESS_CONTEXT_BEGIN(&pbdrv_bluetooth_spi_process);
etimer_set(&observe_restart_timer, OBSERVE_RESTART_INTERVAL);
PROCESS_CONTEXT_END(&pbdrv_bluetooth_spi_process);
observe_restart_enabled = true;
}

PT_END(pt);
Expand Down Expand Up @@ -966,6 +979,11 @@ static PT_THREAD(observe_task(struct pt *pt, pbio_task_t *task)) {

device_discovery_done = false;
is_observing = true;

PROCESS_CONTEXT_BEGIN(&pbdrv_bluetooth_spi_process);
etimer_set(&observe_restart_timer, OBSERVE_RESTART_INTERVAL);
PROCESS_CONTEXT_END(&pbdrv_bluetooth_spi_process);
observe_restart_enabled = true;
}

task->status = PBIO_SUCCESS;
Expand Down Expand Up @@ -1000,6 +1018,8 @@ static PT_THREAD(stop_observe_task(struct pt *pt, pbio_task_t *task)) {

void pbdrv_bluetooth_stop_observing(void) {
observe_callback = NULL;
// avoid restarting observing even if this task get queued
observe_restart_enabled = false;

static pbio_task_t task;
start_task(&task, stop_observe_task, NULL);
Expand Down Expand Up @@ -1959,7 +1979,8 @@ PROCESS_THREAD(pbdrv_bluetooth_spi_process, ev, data) {
PROCESS_EXITHANDLER({
spi_set_mrdy(false);
bluetooth_reset(RESET_STATE_OUT_LOW);
bluetooth_ready = pybricks_notify_en = uart_tx_notify_en = is_broadcasting = is_observing = false;
bluetooth_ready = pybricks_notify_en = uart_tx_notify_en =
is_broadcasting = is_observing = observe_restart_enabled = false;
conn_handle = remote_handle = remote_lwp3_char_handle = NO_CONNECTION;

pbio_task_t *task;
Expand Down Expand Up @@ -2018,6 +2039,14 @@ PROCESS_THREAD(pbdrv_bluetooth_spi_process, ev, data) {
for (;;) {
PROCESS_WAIT_UNTIL({
for (;;) {
if (observe_restart_enabled && etimer_expired(&observe_restart_timer)) {
static pbio_task_t observe_restart_task;
pbdrv_bluetooth_start_observing_callback_t callback = observe_callback;

pbdrv_bluetooth_stop_observing();
pbdrv_bluetooth_start_observing(&observe_restart_task, callback);
}

pbio_task_t *current_task = list_head(task_queue);

if (!current_task) {
Expand Down

0 comments on commit 4158c77

Please sign in to comment.