embedded-linuxuartbluezhci

BlueZ: No default controller available


I'm setting up Linux device to act as BLE host, and ESP32 to work as a BLE controller over UART.

I'm using BlueZ v5.55, with btattach and bluetoothctl utilities, and bluetoothd running in the background. However, after finishing the setup bluetoothctl still says No default controller available.

# /usr/bin/btattach -B /dev/ttymxc1 -S 921600 --protocol h4 &
# Attaching Primary controller to /dev/ttymxc1
Switched line discipline from 0 to 15
Device index 0 attached

# /usr/libexec/bluetooth/bluetoothd

# bluetoothctl
Agent registered
[bluetooth]# power on
No default controller available

Output of btmon:

# btmon
Bluetooth monitor ver 5.55
= Note: Linux version 5.4.8 (armv7l)                                                                                                  0.258161
= Note: Bluetooth subsystem version 2.22                                                                                              0.258269
= New Index: 00:00:00:00:00:00 (Primary,UART,hci0)                                                                             [hci0] 0.258314
@ MGMT Open: bluetoothd (privileged) version 1.14                                                                            {0x0001} 0.258357

Output of dmesg during kernel start:

# dmesg | grep Blu
[    0.643821] Bluetooth: Core ver 2.22
[    0.644222] Bluetooth: HCI device and connection manager initialized
[    0.644528] Bluetooth: HCI socket layer initialized
[    0.644622] Bluetooth: L2CAP socket layer initialized
[    0.645069] Bluetooth: SCO socket layer initialized
[    4.678559] Bluetooth: HCI UART driver ver 2.3
[    4.683346] Bluetooth: HCI UART protocol H4 registered
[    4.688821] Bluetooth: HCI UART protocol LL registered

The ESP32 is running UART HCI controller firmware: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/hci/controller_hci_uart

The host is running a Buildroot-created Linux with BR2_PACKAGE_BLUEZ_TOOLS=y and a kernel with CONFIG_BT=y, CONFIG_BT_LE=y, CONFIG_BT_HCIUART=y, CONFIG_BT_HCIUART_H4=y.

I have 4 UART lines connected TX->RX, RX->TX, RTS->CTS and CTS->RTS.

I have checked the UART communication with the same HW setup - I can exchange data over UART with the ESP32 (in both directions).

The commands are run as root.

What am I missing here? If you have any decent documentation on BlueZ HCI setup, I'll be happy to see it.

EDIT: I also installed hcidump and hciconfig (normally deprecated in BLueZ v5.55). Here is a log from hcidump:

# hcidump  
HCI sniffer - Bluetooth packet analyzer ver 5.55
device: hci0 snap_len: 1500 filter: 0xffffffff

< HCI Command: Read Local Supported Features (0x04|0x0003) plen 0
< HCI Command: Read Local Version Information (0x04|0x0001) plen 0
< HCI Command: Read BD ADDR (0x04|0x0009) plen 0

(in 2nd terminal)
# hciconfig hci0 up
Can't init device hci0: Connection timed out (110)

Solution

  • After a few days, I have found a solution of this problem.

    I have also used nRF52 DK as an alternative to better understand if the problem lies on the side of ESP32 controller, or on the side of Linux host. Because the nRF HCI UART worked on Ubuntu 20.04, but didn't work on my embedded Linux, I looked deeper on the Linux host side.

    After starting BlueZ daemon with bluetoothd -n it showed more details:

    bluetoothd[593]: src/adapter.c:get_static_addr() Failed to open crypto
    bluetoothd[593]: No Bluetooth address for index 0
    

    Which led me to this topic: https://github.com/raspberrypi/linux/issues/3628

    It turns out, when attaching the UART HCI controller with btattach, BlueZ was not able to create a static address, because of missing Linux kernel crypto interface in user-space.

    I compiled the kernel with additional configs:

    CONFIG_CRYPTO_USER
    CONFIG_CRYPTO_USER_API
    CONFIG_CRYPTO_USER_API_AEAD
    CONFIG_CRYPTO_USER_API_HASH
    
    CONFIG_CRYPTO_AES
    CONFIG_CRYPTO_CCM
    CONFIG_CRYPTO_AEAD
    CONFIG_CRYPTO_CMAC
    

    After that change, I was able to attach the Bluetooth controller to my Embedded Linux host.