From b301d97d0cee075a8e500d6b496fa86378e07140 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sat, 4 Nov 2023 16:13:46 -0500 Subject: [PATCH] drv/bluetooth_stm32_cc2640: fix broadcast lockup This changes the command to update advertising data on the Bluetooth chip in the broadcast task to use HCI_LE_setAdvertisingData() instead of GAP_updateAdvertisingData(). It appears there is some sort of memory leak or some such on the Bluetooth chip that causes it to lock up if we call the vendor-specific GAP_updateAdvertisingData() too many times. It appears that we can work around this by calling the standard Bluetooth command HCI_LE_setAdvertisingData() instead. GAP_updateAdvertisingData() would result in two events being sent back from the Bluetooth chip, a status event and a command complete event. With HCI_LE_setAdvertisingData() we only get a command complete event back - with the TI vendor-specific opcode as if we had called GAP_updateAdvertisingData(). Fixes: https://github.com/pybricks/support/issues/1095 --- CHANGELOG.md | 2 ++ lib/ble5stack/central/hci.c | 12 ++++++++++++ lib/ble5stack/central/hci.h | 1 + lib/ble5stack/central/hci_tl.h | 1 + lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c | 15 ++++++--------- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c84d067de..fb82d2330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ ### Fixed - Fixed Move Hub accelerometer not working since v3.3.0b5 ([support#1269]). +- Fixed Bluetooth chip locking up on Technic and City hubs when broadcasting ([[support#1095]]). +[support#1095]: https://github.com/pybricks/support/issues/1095 [support#1269]: https://github.com/pybricks/support/issues/1269 ## [3.3.0b9] - 2023-10-26 diff --git a/lib/ble5stack/central/hci.c b/lib/ble5stack/central/hci.c index dd6380ec7..b5ad8ddd5 100644 --- a/lib/ble5stack/central/hci.c +++ b/lib/ble5stack/central/hci.c @@ -1,4 +1,6 @@ +#include + #include "hci_tl.h" HCI_StatusCodes_t HCI_readBdaddr(void) @@ -15,3 +17,13 @@ HCI_StatusCodes_t HCI_LE_readAdvertisingChannelTxPower(void) { return HCI_sendHCICommand(HCI_LE_READ_ADVERTISING_CHANNEL_TX_POWER, NULL, 0); } + +HCI_StatusCodes_t HCI_LE_setAdvertisingData(uint8_t len, uint8_t *data) +{ + uint8_t pData[32]; + + pData[0] = len; + memcpy(&pData[1], data, len); + + return HCI_sendHCICommand(HCI_LE_SET_ADVERTISING_DATA, pData, len + 1); +} diff --git a/lib/ble5stack/central/hci.h b/lib/ble5stack/central/hci.h index 35c8fc967..dfc303300 100644 --- a/lib/ble5stack/central/hci.h +++ b/lib/ble5stack/central/hci.h @@ -6,5 +6,6 @@ HCI_StatusCodes_t HCI_readBdaddr(void); HCI_StatusCodes_t HCI_readLocalVersionInfo(void); HCI_StatusCodes_t HCI_LE_readAdvertisingChannelTxPower(void); +HCI_StatusCodes_t HCI_LE_setAdvertisingData(uint8_t len, uint8_t *data); #endif // HCI_H diff --git a/lib/ble5stack/central/hci_tl.h b/lib/ble5stack/central/hci_tl.h index a640d6afb..a60b6a2df 100755 --- a/lib/ble5stack/central/hci_tl.h +++ b/lib/ble5stack/central/hci_tl.h @@ -98,6 +98,7 @@ // Low energy commands #define HCI_LE_READ_ADVERTISING_CHANNEL_TX_POWER 0x2007 //!< opcode of @ref HCI_LE_readAdvertisingChannelTxPower +#define HCI_LE_SET_ADVERTISING_DATA 0x2008 /* HCI Status return types */ typedef enum diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c index 00d46e059..40dd07c3d 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c @@ -827,16 +827,13 @@ static PT_THREAD(broadcast_task(struct pt *pt, pbio_task_t *task)) { PT_EXIT(pt); } + // 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- + // specific command complete event as if we had called the TI command (but + // not the command status). 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); - - if (read_buf[8] != bleSUCCESS) { - task->status = ble_error_to_pbio_error(read_buf[8]); - PT_EXIT(pt); - } - - // wait for GAP update advert data done event + HCI_LE_setAdvertisingData(value->size, value->data); PT_WAIT_UNTIL(pt, hci_command_complete); if (!is_broadcasting) {