Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
- Extensive overhaul of UART and port drivers on all hubs. This affects all
official LEGO sensors on all hubs.

### Fixed
- Reduced hanging when broadcasting and observing at the same time with Technic
Hub ([support#2206]).

[support#220]: https://github.com/pybricks/support/issues/220
[support#2206]: https://github.com/pybricks/support/issues/2206
[pybricks-micropython#208]: https://github.com/pybricks/pybricks-micropython/pull/208

## [3.6.1] - 2025-03-11
Expand Down
44 changes: 30 additions & 14 deletions lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ static const pbdrv_bluetooth_stm32_cc2640_platform_data_t *pdata = &pbdrv_blueto
#define SCAN_RESTART_INTERVAL 3000
#define OBSERVE_RESTART_INTERVAL 10000
static struct etimer scan_restart_timer;
static struct etimer observe_restart_timer;
static bool observe_restart_enabled;
static bool observe_restart_requested;
static uint32_t observe_restart_time;

/**
* Converts a ble error code to the most appropriate pbio error code.
Expand Down Expand Up @@ -500,7 +500,6 @@ static PT_THREAD(peripheral_scan_and_connect_task(struct pt *pt, pbio_task_t *ta

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

PT_WAIT_WHILE(pt, write_xfer_size);
GAP_DeviceDiscoveryCancel();
Expand Down Expand Up @@ -747,10 +746,8 @@ static PT_THREAD(peripheral_scan_and_connect_task(struct pt *pt, pbio_task_t *ta

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;
observe_restart_time = pbdrv_clock_get_ms();
observe_restart_requested = false;
}

PT_END(pt);
Expand Down Expand Up @@ -1073,13 +1070,26 @@ void pbdrv_bluetooth_peripheral_disconnect(pbio_task_t *task) {
static PT_THREAD(broadcast_task(struct pt *pt, pbio_task_t *task)) {
pbdrv_bluetooth_value_t *value = task->context;

static struct {
pbdrv_bluetooth_value_t v;
uint8_t d[31];
} previous_value;

PT_BEGIN(pt);

if (value->size > B_MAX_ADV_LEN) {
task->status = PBIO_ERROR_INVALID_ARG;
PT_EXIT(pt);
}

// Avoid I/O operations if the user tries to broadcast the same data
// over and over in a tight loop.
if (is_broadcasting && !memcmp((void *)&previous_value, (void *)value, sizeof(pbdrv_bluetooth_value_t) + value->size)) {
task->status = PBIO_SUCCESS;
PT_EXIT(pt);
}
memcpy((void *)&previous_value, (void *)value, sizeof(pbdrv_bluetooth_value_t) + value->size);

// HACK: calling GAP_updateAdvertisingData() repeatedly will cause the
// Bluetooth chips on Technic and City hubs to eventually lock up. So we
// call the standard Bluetooth command instead. We still get the vendor-
Expand Down Expand Up @@ -1162,10 +1172,8 @@ 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;
observe_restart_time = pbdrv_clock_get_ms();
observe_restart_requested = false;
}

task->status = PBIO_SUCCESS;
Expand Down Expand Up @@ -1201,11 +1209,16 @@ static PT_THREAD(stop_observe_task(struct pt *pt, pbio_task_t *task)) {
void pbdrv_bluetooth_stop_observing(pbio_task_t *task) {
observe_callback = NULL;
// avoid restarting observing even if this task get queued
observe_restart_enabled = false;
observe_restart_requested = false;

start_task(task, stop_observe_task, NULL);
}

void pbdrv_bluetooth_restart_observing_request(void) {
observe_restart_requested = true;
process_poll(&pbdrv_bluetooth_spi_process);
}

// Driver interrupt callbacks

void pbdrv_bluetooth_stm32_cc2640_srdy_irq(bool srdy) {
Expand Down Expand Up @@ -2250,7 +2263,7 @@ PROCESS_THREAD(pbdrv_bluetooth_spi_process, ev, data) {
spi_set_mrdy(false);
bluetooth_reset(RESET_STATE_OUT_LOW);
bluetooth_ready = pybricks_notify_en = uart_tx_notify_en =
is_broadcasting = is_observing = observe_restart_enabled = false;
is_broadcasting = is_observing = observe_restart_requested = false;
conn_handle = peripheral_singleton.con_handle = NO_CONNECTION;

pbio_task_t *task;
Expand Down Expand Up @@ -2309,11 +2322,14 @@ PROCESS_THREAD(pbdrv_bluetooth_spi_process, ev, data) {
for (;;) {
PROCESS_WAIT_UNTIL({
for (;;) {
if (observe_restart_enabled && etimer_expired(&observe_restart_timer)) {
if (observe_restart_requested && pbdrv_clock_get_ms() - observe_restart_time > OBSERVE_RESTART_INTERVAL) {
static pbio_task_t observe_restart_stop_task;
static pbio_task_t observe_restart_start_task;
pbdrv_bluetooth_start_observing_callback_t callback = observe_callback;

// Avoid queueing this more than once.
observe_restart_time = pbdrv_clock_get_ms();

pbdrv_bluetooth_stop_observing(&observe_restart_stop_task);
pbdrv_bluetooth_start_observing(&observe_restart_start_task, callback);
}
Expand Down
6 changes: 6 additions & 0 deletions pybricks/common/pb_type_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,12 @@ static mp_obj_t pb_module_ble_observe(mp_obj_t self_in, mp_obj_t channel_in) {

// Have not received data yet or timed out.
if (ch_data.rssi == INT8_MIN) {

#if PBDRV_CONFIG_BLUETOOTH_STM32_CC2640
extern void pbdrv_bluetooth_restart_observing_request(void);
pbdrv_bluetooth_restart_observing_request();
#endif

return mp_const_none;
}

Expand Down