Skip to content

Commit

Permalink
drv/bluetooth_stm32_cc2640: work around broadcast lock up
Browse files Browse the repository at this point in the history
The Bluetooth chips on the Technic and City hubs seem to lock up if
the advertisement date is updated too many times. So far, we have only
found one condition where this doesn't happen. The Bluetooth chip
can't be connected to any other devices and advertising has to be
stopped and restarted between each update. This is quite limiting,
but seems to be the best we can do for now.

Issue: pybricks/support#1095
  • Loading branch information
dlech committed Nov 4, 2023
1 parent 4d386be commit 9ec50d0
Showing 1 changed file with 46 additions and 24 deletions.
70 changes: 46 additions & 24 deletions lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,28 @@ static PT_THREAD(broadcast_task(struct pt *pt, pbio_task_t *task)) {
PT_EXIT(pt);
}

// Unfortunately, the Bluetooth chip on the Technic and City hubs will
// eventually crash if we keep updating the advertising data when connected
// to something else at the same time. So we can't permit this operation
// when connected to something else.
if (conn_handle != NO_CONNECTION || remote_handle != NO_CONNECTION) {
task->status = PBIO_ERROR_INVALID_OP;
PT_EXIT(pt);
}

// Even when not connected to something else, the Bluetooth chip will still
// eventually lock up unless we stop and restart advertising.
if (is_broadcasting) {
PT_WAIT_WHILE(pt, write_xfer_size);
GAP_endDiscoverable();
PT_WAIT_UNTIL(pt, hci_command_status);

if (read_buf[8] == bleSUCCESS) {
// wait for discovery cancel done event
PT_WAIT_UNTIL(pt, hci_command_complete);
}
}

PT_WAIT_WHILE(pt, write_xfer_size);
GAP_updateAdvertisingData(GAP_AD_TYPE_ADVERTISEMENT_DATA, value->size, value->data);
PT_WAIT_UNTIL(pt, hci_command_status);
Expand Down Expand Up @@ -865,34 +887,34 @@ static PT_THREAD(broadcast_task(struct pt *pt, pbio_task_t *task)) {
PT_WAIT_UNTIL(pt, hci_command_status);
// ignoring response data

PT_WAIT_WHILE(pt, write_xfer_size);
GAP_makeDiscoverable(
#if PBDRV_CONFIG_BLUETOOTH_STM32_CC2640_QUIRK_BROKEN_NONCONN_IND
// City hub fails to send non-connectable advertisements so we
// have to use the wrong advertisement type to get it to actually
// send something over the air.
ADV_IND,
#else
// Technic hub will send non-connectable advertisements only if
// it is connected to something else, otherwise we need the same
// hack as the City hub.
(conn_handle == NO_CONNECTION && remote_handle == NO_CONNECTION) ? ADV_IND : ADV_NONCONN_IND,
#endif
GAP_INITIATOR_ADDR_TYPE_PRIVATE_NON_RESOLVE, NULL,
GAP_CHANNEL_MAP_ALL, GAP_FILTER_POLICY_SCAN_ANY_CONNECT_ANY);
PT_WAIT_UNTIL(pt, hci_command_status);

if (read_buf[8] != bleSUCCESS) {
task->status = ble_error_to_pbio_error(read_buf[8]);
PT_EXIT(pt);
}
is_broadcasting = true;
}

// wait for make discoverable done event
PT_WAIT_UNTIL(pt, hci_command_complete);
PT_WAIT_WHILE(pt, write_xfer_size);
GAP_makeDiscoverable(
#if PBDRV_CONFIG_BLUETOOTH_STM32_CC2640_QUIRK_BROKEN_NONCONN_IND
// City hub fails to send non-connectable advertisements so we
// have to use the wrong advertisement type to get it to actually
// send something over the air.
ADV_IND,
#else
// Technic hub will send non-connectable advertisements only if
// it is connected to something else, otherwise we need the same
// hack as the City hub.
(conn_handle == NO_CONNECTION && remote_handle == NO_CONNECTION) ? ADV_IND : ADV_NONCONN_IND,
#endif
GAP_INITIATOR_ADDR_TYPE_PRIVATE_NON_RESOLVE, NULL,
GAP_CHANNEL_MAP_ALL, GAP_FILTER_POLICY_SCAN_ANY_CONNECT_ANY);
PT_WAIT_UNTIL(pt, hci_command_status);

is_broadcasting = true;
if (read_buf[8] != bleSUCCESS) {
task->status = ble_error_to_pbio_error(read_buf[8]);
PT_EXIT(pt);
}

// wait for make discoverable done event
PT_WAIT_UNTIL(pt, hci_command_complete);

task->status = PBIO_SUCCESS;

PT_END(pt);
Expand Down

0 comments on commit 9ec50d0

Please sign in to comment.