From d92f48f4e752a62c9c64da9ccac310c0861c593f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 16 Sep 2022 11:20:36 -0500 Subject: [PATCH] drv/bluetooth_stm32_bluenrg: new random address on each reset The BlueNRG-MS chip always uses the same random address. We would like to use a new random address on each reset to work around BlueZ bugs like Chrome causing duplicate notifications after a device disconnects. Issue: https://github.com/pybricks/support/issues/600 --- lib/BlueNRG-MS/hci/hci_le.c | 47 ++++++++----------- lib/BlueNRG-MS/includes/hci_le.h | 6 ++- .../drv/bluetooth/bluetooth_stm32_bluenrg.c | 19 ++++++++ 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/lib/BlueNRG-MS/hci/hci_le.c b/lib/BlueNRG-MS/hci/hci_le.c index 78a97cb47..12181a0de 100644 --- a/lib/BlueNRG-MS/hci/hci_le.c +++ b/lib/BlueNRG-MS/hci/hci_le.c @@ -250,29 +250,30 @@ int hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) return status; } -int hci_le_rand(uint8_t random_number[8]) +void hci_le_rand_begin(void) { - struct hci_request_and_response rq; - le_rand_rp resp; - - memset(&resp, 0, sizeof(resp)); + struct hci_request rq; - memset(&rq, 0, sizeof(rq)); rq.opcode = cmd_opcode_pack(OGF_LE_CTL, OCF_LE_RAND); rq.cparam = NULL; rq.clen = 0; - rq.rparam = &resp; - rq.rlen = LE_RAND_RP_SIZE; - hci_send_req_recv_rsp(&rq); + hci_send_req(&rq); +} - if (resp.status) { - return resp.status; - } +tBleStatus hci_le_rand_end(uint8_t *random_number) +{ + struct hci_response rq; + le_rand_rp resp; - memcpy(random_number, resp.random, 8); + rq.rparam = &resp; + rq.rlen = sizeof(resp); - return 0; + hci_recv_resp(&rq); + + memcpy(random_number, resp.random, sizeof(resp.random)); + + return resp.status; } void hci_le_set_scan_response_data_begin(uint8_t length, const uint8_t *data) @@ -317,25 +318,15 @@ int hci_le_read_advertising_channel_tx_power(int8_t *tx_power_level) return 0; } -int hci_le_set_random_address(tBDAddr bdaddr) +void hci_le_set_random_address_begin(tBDAddr bdaddr) { - struct hci_request_and_response rq; - le_set_random_address_cp set_rand_addr_cp; - uint8_t status; - - memset(&set_rand_addr_cp, 0, sizeof(set_rand_addr_cp)); - memcpy(set_rand_addr_cp.bdaddr, bdaddr, sizeof(tBDAddr)); + struct hci_request rq; - memset(&rq, 0, sizeof(rq)); rq.opcode = cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_RANDOM_ADDRESS); - rq.cparam = &set_rand_addr_cp; + rq.cparam = bdaddr; rq.clen = LE_SET_RANDOM_ADDRESS_CP_SIZE; - rq.rparam = &status; - rq.rlen = 1; - hci_send_req_recv_rsp(&rq); - - return status; + hci_send_req(&rq); } int hci_read_bd_addr(tBDAddr bdaddr) diff --git a/lib/BlueNRG-MS/includes/hci_le.h b/lib/BlueNRG-MS/includes/hci_le.h index 7de168134..debdbd013 100644 --- a/lib/BlueNRG-MS/includes/hci_le.h +++ b/lib/BlueNRG-MS/includes/hci_le.h @@ -134,13 +134,15 @@ void hci_le_set_advertising_data_begin(uint8_t length, const uint8_t *data); void hci_le_set_scan_response_data_begin(uint8_t length, const uint8_t *data); #define hci_le_set_scan_response_data_end hci_le_command_end -int hci_le_rand(uint8_t random_number[8]); +void hci_le_rand_begin(void); +tBleStatus hci_le_rand_end(uint8_t *random_number); int hci_le_read_advertising_channel_tx_power(int8_t *tx_power_level); int hci_acl_data(const uint8_t * data, uint16_t len); -int hci_le_set_random_address(tBDAddr bdaddr); +void hci_le_set_random_address_begin(tBDAddr bdaddr); +#define hci_le_set_random_address_end hci_le_command_end int hci_read_bd_addr(tBDAddr bdaddr); diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c index 187626493..28a32b55c 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c @@ -1128,6 +1128,25 @@ static PT_THREAD(hci_init(struct pt *pt)) { PT_WAIT_UNTIL(pt, hci_command_complete); aci_gatt_update_char_value_end(); + // The chip always uses the same random address, so we have to generate + // an actually random one to get a new address each time. This must be + // called after aci_gap_init to take effect. + + // STM32F0 doesn't have a random number generator, so we use the bluetooth + // chip to get some random bytes. + hci_le_rand_begin(); + PT_WAIT_UNTIL(pt, hci_command_complete); + { + uint8_t rand_buf[8]; + hci_le_rand_end(rand_buf); + + // hard-coding MSB to meet requirements of static random address + rand_buf[5] = 0xF0; + hci_le_set_random_address_begin(rand_buf); + } + PT_WAIT_UNTIL(pt, hci_command_complete); + hci_le_set_random_address_end(); + PT_END(pt); }