Cannot complete a bt connection after last update to v2.3.0 #3106
Labels
No labels
bazel
bluetooth
board settings
boot_stage2
bug
build
c++
can't reproduce
clang
clib-interface
cmsis
code cleanliness
code size
compiler version issues
cyw43_driver
debug
discussion
documentation
duplicate
dynamic_clock
elf2uf2
enhancement
errata
filesystem
flash layout
floating point
FreeRTOS
hardware_adc
hardware_claim
hardware_clocks
hardware_dma
hardware_exception
hardware_flash
hardware_gpio
hardware_i2c
hardware_irq
hardware_pio
hardware_pwm
hardware_rcp
hardware_rtc
hardware_spi
hardware_sync
hardware_uart
hardware_vreg
hardware_watchdog
hardware_xosc
help wanted
host
IAR
installation
invalid
linker scripts
lto
lwip
mbedtls
missing API
needs reporter detail
networking
newlib
newlib-multicore
non-c
non-cmake
non-gcc
openocd
orphan PR
OS integration
pico_async_context
pico_base
pico_binary_info
pico_flash
picolibc
pico_lwip
pico_malloc
pico_multicore
pico_printf
pico_runtime
pico_stdio
pico_stdio_usb
pico_sync
pico_time
pico_util
pioasm
port
question
review
review2
rtos interop
runtime init
static library
svd
test
tinyusb
vscode
wifi integration
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-raspberrypi/pico-sdk#3106
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Hello,
I am building a device that streams Bluetooth audio using the A2DP protocol over I2S to a DAC, in order to play music from my phone to a set of speakers. I am using the Pimoroni Pico 2 W Plus.
For this project, I based my code on the btstack example a2dp_sink_demo.c found in pico-examples. I am using FreeRTOS to manage the various tasks, and I have a dedicated task for the btstack loop.
Anyway, the issue I am experiencing can also be reproduced with just the aforementioned example; in fact, the Bluetooth handling code in my project is almost identical.
The problem is that I cannot connect to the phone after updating to the latest version of the pico-sdk (v2.3.0), and consequently to btstack version 1.8.2. (The btstack changelog mentions an increased security level in this release.) Let me explain further: the pairing between the device and the phone, when initiating the request from the phone, is successful and I am able to connect; however, after a reboot using the following function
where
device_addris the MAC address of my phone a Pixel 8a,as you can see in the log AudioPico_Pixel_connection_failed.pklg, it returns:
After several tests and attempts, my guess is that the process might be failing after authentication when requesting to raise the security level at the following line:
Looking at the log from the phone's perspective in the Pixel_AudioPico_connection_failed.pcapng file, after the line below, the Pico sends the disconnect command. I assume because the security levels do not match, meaning level 2 is requested but the current level is 0:
The same code works with pico-sdk 2.2.0.
I noticed another thing: when I compile with the latest SDK version and pair, after rebooting I initially get error 0x66 which is
L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY,I noticed from the logs that the Link Key was reversed; by executing a function to reverse it and saving it, the error goes back to being 0x6a orL2CAP_CONNECTION_BASEBAND_DISCONNECT. I know the key is correct reversed because if I flash the code compiled with the old sdk it works without need to pair, in fact the keys are saved in flash via the TLV functions.This is my function to initialize the various bluetooth protocols:
This is my btstack_config.h
Here it's the Drive folder with all the logs1, since Wireshark captures are not supported in GitHub.
As I mentioned, I also tried using only the example code compiled with the latest SDK, and the behavior is the same. I am attaching logs named Example_Pixel or Pixel_Example which refer to the format described in the notes.
The file Pixel_AudioPico_Pairing contains the log of a successful pairing.
The file Pixel_AudioPico_connection_successful_old contains the log of a successful connection between the Pixel and the Pico (also initiated by the Pico) using version 2.2.0.
My final question is: how can I solve this issue? I have also tried all the various security settings in the new version of BTstack, but nothing seems to work.
I tried changing devices by using an iPad running iOS 18.7.9 and a MacBook Air running macOS 26, but the behavior remains the same and the Pico log is practically identical.
Thanks, any help would be greatly appreciated,
Mattia.
The file naming follows this format: Source_Destination_type_of_log e.g. AudioPico_Pixel_connection_failed indicates the log extracted from the Pico trying to connect to the phone, while Pixel_AudioPico indicates the log extracted from the phone trying to connect to the Pico. ↩︎
Hello,
I've hit the same issue after updating to pico-sdk 2.3.0.
The issue appears to stem from two independent problems, both in btstack.
The first cause is btstack
hci_stack->ssp_auto_acceptinbtstack/src/hci.cdefaulting to 0 as of version 1.8.2 - the SSP confirmation reply gets blocked without setting it to 1 explicitly. The default flipped from 1 to 0 specifically between v1.8.1 and v1.8.2.The second cause appears to lie in btstack's HCI dispatch design:
static void hci_run()inbtstack/src/hci.cdispatches at most one pending item per call and relies on being re-invoked externally to drain anything further. pico-sdk PR #3042 removed a self-emitted HCI_EVENT_TRANSPORT_PACKET_SENT that had been incidentally providing that re-invocation immediately after every send. The PR itself is a correct fix.The regression is a side effect: with the self-emit gone, a second pending item that becomes ready right after the first dispatch now has to wait for some other real packet to arrive before hci_run() gets re-invoked. This bites outgoing connections in particular because
btstack/src/classic/hid_host.cdoesn't request the security level until well after the ACL link is up - so the authenticate -> encrypt -> read-key-size chain kicks off late, in a quiet window with little other packet traffic to accidentally trigger hci_run() again.I was able to get my Pico working with either of the following approaches:
1. Proactively request security LEVEL_2 when a Pico-initiated connection completes.
2. Patch btstack version 1.8.2
hci_run()directly.This addresses the root cause: rather than depending on external re-invocation,
hci_run()drains everything it can in a single call. Apply the diff from within the Pico SDK checkout'slib/btstackdirectory:Hope this helps,
- Hiroshi
Thanks a lot, it works flawlessly!! 😃 I just tested your first approach and it connects right away!
Anyway the definitive solution is to ask to modify btstack or is it intended behaviour to proactively request higher security level?
Mattia.
Can you test with develop which has a newer vesion of btstack? https://github.com/raspberrypi/pico-sdk/pull/3123
It looks like this change in 2.3.0 caused a regression https://github.com/raspberrypi/pico-sdk/pull/3042
This looks like a btstack bug. Investigating.
@Elrir94
Glad to hear it worked for you!
Normally, apps shouldn't need to call
gap_request_security_level()themselves.hid_host.calready calls it internally vial2cap_create_channel(..., sec_level=2)when it opens the HID Control L2CAP channel, and from there btstack transitions the security level automatically: it kicks off the authenticate -> encrypt -> read-key-size chain without further app involvement.On pico-sdk 2.3.0, though, that automatic transition stalls right after encryption completes, specifically at the BONDING_SEND_READ_ENCRYPTION_KEY_SIZE step. The flag gets set, but nothing re-invokes
hci_run()to actually dispatch the Read_Encryption_Key_Size command.I'm not sure whether
hci_run()'s external-re-invocation-reliant design was ever meant to be a hard guarantee, but it does appear to be original and unchanged. The "dispatch one item, then return" pattern predates the 2020 refactor and is applied uniformly across the whole function, not something specific to this bonding step. Given that, patchinghci_run()to loop instead of return seems like the more logical fix: it addresses the dispatch mechanism itself, not just the bonding step that happened to expose it, so it should also cover any other pending item that becomes ready right after another dispatch, not just BONDING_SEND_READ_ENCRYPTION_KEY_SIZE.- Hiroshi
@peterharperuk
Thank you! The develop fixes the bonding issue. Confirmed that
hci.c'shci_schedule_transport_packet_sent()re-emitsHCI_EVENT_TRANSPORT_PACKET_SENTby registering a callback viabtstack_run_loop_execute_on_main_thread(), which on the Pico gets queued through the async_context worker.- Hiroshi
This fixes the "key is stored reversed" problem for me. https://github.com/bluekitchen/btstack/pull/745
@peterharperuk I just tried the develop branch and,as @hiromorii said, it fixes the bonding problem, without the need for proactively requesting security level 2. However the "reversed key problem" persists and i have to manually reverse it and save again to make it work.
You need this fix https://github.com/bluekitchen/btstack/pull/745 It has not been merged yet