USB Protocol Analyzer for Bluetooth Communication Logging

When a Bluetooth use case doesn’t work as expected, it’s often very helpful to analyze the Bluetooth communication.

If one side is using BTstack, a good way for this is to just enable HCI Packet Log, convert the console output with the create_packet_log.py tool and then inspect it with Apple’s PacketLogger (macOS only) or Wireshark (any platform). By this, the debug output is captured in-line with the Bluetooth packets, which makes them much easier to analyze.

If you are not using BTstack, but the other side is either macOS or Linux, you can also get an HCI Log via PacketLogger (macOS) resp. hci_dump (from Linux’ blueZ Bluetooth stack).

As for Windows, we can either try to log the USB traffic locally (e.g. somehow running a Windows VM on Linux and capturing the USB data) or connect a USB Bluetooth Dongle and use a USB Protocol Analyzer. Here’s our experience using the Beagle USB 12 Protocol Analyzer to log Bluetooth communication directly at the USB port.

HCI Packet Logging of Bluetooth USB Dongles with a TotalPhase Beagle USB Protocol Analyzer

After registration, the TotalPhase’s Beagle Software API is available for Mac/Win/Linux in 32-bit and 64-bit versions. The SDK contains drivers and examples in C, C#, .NET, Python, and Visual Basic. We’ve picked Python as it’s cross-platform and fast to develop for. After setting up the hardware, with the Beagle USB 12 between the USB Bluetooth Dongle and the host PC, the capture_usb12.py example prints out a lot of data out when Bluetooth is active.

There are four different Bluetooth HCI packet types: HCI Commands, HCI Events, HCI ACL and HCI SCO packets. A closer look to the console log showed the expected HCI packets, e.g. an HCI Reset (03 0c 00)

3,2177839916,USB,( OK ),SETUP,2d 40 48 
4,2177843187,USB,( OK ),DATA0,c3 21 00 00 00 00 00 03 00 7c d0 
5,2177851812,USB,( OK ),ACK,d2 
6,2177853312,USB,( ),COLLAPSED [1 IN/NAK] 
7,2177860958,USB,( OK ),OUT,e1 40 48 
8,2177864229,USB,( OK ),DATA1,4b 03 0c 00 7b 3f               // HCI Reset Command
9,2177869645,USB,( OK ),ACK,d2 

and the corresponding HCI Command Complete Event (0e 04 01 03 0c 00)

10,2177877854,USB,( OK ),IN,69 40 48 
11,2177881145,USB,( OK ),DATA1,4b 00 00 
12,2177884416,USB,( OK ),ACK,d2 
13,2177885916,USB,( ),COLLAPSED [4 SOF] [139 IN/NAK] 
14,2181820833,USB,( OK ),IN,69 c0 f8 
15,2181824166,USB,( OK ),DATA0,c3 0e 04 01 03 0c 00 fb f6     // HCI Command Complete Event for HCI Reset
16,2181831437,USB,( OK ),ACK,d2 

For now, we ignore HCI SCO packets and “only” have to: – figure out how to distinguish HCI Commands, HCI Events, and HCI ACL packets from each other, and – recombine fragmented packets, as USB Full Speed (12 mbps) used for Bluetooth allows only up to 64 byte USB packets.

We can distinguish the Bluetooth packets by their endpoint type. According to the Bluetooth specification: – HCI Commands are sent to the Control Endpoint, – HCI Events are received on an Interrupt Endpoint, while – ACL packets are sent via Bulk Endpoint.

The device endpoints are described in the device descriptor, which is read by the USB host, e.g. PC, after the USB device is plugged in. For this project, we tried to avoid this unplug/re-plug cycle for every capture, hence we need to find the correct endpoints some other way.

Identifying Bluetooth Endpoints

Note: you can skip this section, if you just want to use the tool.

By monitoring the same data with the official Data Center Software application, we get an insight how different USB packets are used to transfer the HCI data.

Screenshot from Data Center application

Going over the Beyond Logic’s “USB in a Nutshell”, we learn that there are different USB packet types: – token packets: IN, OUT, SETUP – data packets: DATA0, DATA1 – handshake packet: ACK, NACK, STALL – start of frame packets: SOF.

All Token Packets have both an address and an endpoint fields. Data Packets follow the Token packets and don’t have address or endpoint fields. Then, we also learn that a Control transfer requires a Token SETUP packet. After the SETUP, a DATA0 packet is followed by an ACK packet and then an OUT token, followed by the actual data in another DATAx packet and finally an ACK/NACK/STALL packet.

So we can conclude: – if we receive a token SETUP packet, we know that its endpoint is the endpoint for HCI Commands, – if an outgoing packet has an endpoint different from the one in the SETUP packet, it must be an outgoing ACL packet.

Distinguishing between an HCI Event and an incoming HCI ACL packet is more tricky. We decided to cheat a bit (== “we used deep domain-knowledge”) and just assume that ACL packets will only be received after a HCI Connection was created, which requires at least one HCI Event to be received first.

The final rule is as follows: If the Control Endpoint is identified AND we didn’t identify the Interrupt Endpoint for incoming ACL packets yet AND it’s an IN packet AND the endpoint of the IN packet is different from the Control Endpoint, THEN this is the Interrupt Endpoint for incoming ACL packets.

Usage

First, clone the bluetooth-logger project from our GitHub repository.

Then, go to the totalphase-beagle-usb folder and run

./capture_bluetooth_beagle12.py

for the Beagle 12 device, or

./capture_bluetooth_beagle480_5000.py

for the Beagle 480 and 5000 devices. It will create the file hci_dump.pklg in the current directory. The hci_dump.pklg can be then inspected with Apple’s PacketLogger as well as with Wireshark.

Future Work

There are a few use cases where logging via the console UART would make the system too slow to be useful, for example when streaming audio. If you’re using a Bluetooth USB chipset, you can surely use our new USB Protocol Analyzer approach, but in most embedded systems the Bluetooth Controller is connected via an UART instead. Here, it would be quite useful to use a logic analyzer to capture Bluetooth HCI traces right at the Bluetooth Controller’s UART.

Assuming that most controllers start up at 115200, it should even be possible to hook up two probes to RX and TX and let the tool figure out which one is which.

In addition, we could add logic to detect the HCI Commands for baud rate changes for common controllers (TI, Broadcom, CSR, Toshiba, EM..) and automatically follow the baud changes. Also, a third probe could be connected to the console UART to capture debug output in-line with the Bluetooth packets, which makes them much easier to analyze – similar to BTstack’s packet log, but without performance impact.

Storing Link Keys in Flash Memory
Making Your Own Adapters