Host Controller Interface in BLE – bluetooth low energy tutorial

 

Chapter 9 — Host Controller Interface
HCI Introduction, Packet Formats, OGF 0x08, LE Meta Event 0x3E & Full Table 9.1 Command Reference
LE OGF
0x08
Meta Event
Code 0x3E
LE Prefix
HCI_LE_*
No SCO
LE HCI only
Keywords:

BLE HCI host controller interface BLE HCI command OGF 0x08 BLE LE Meta Event 0x3E BLE HCI subevent code BLE HCI ACL data packet BLE dual mode backward compatible BLE HCI command table 9.1 BlueZ HCI LE commands

9.1 — What Is the HCI and Why Does It Exist?

In most Bluetooth implementations the software and the radio hardware live on two separate chips. The host is the main application processor — a CPU running an operating system, the Bluetooth host stack, and the application. The controller is a dedicated Bluetooth chip that handles the radio, the link layer, and the physical layer.

These two chips need to talk to each other. The Host Controller Interface (HCI) is the standardised protocol that defines exactly how they communicate — what commands the host can send to the controller, what events the controller sends back to the host, and how data packets flow between them. Without a standard interface, every Bluetooth chip would need its own custom driver.

Where HCI Sits in the BLE Protocol Stack

HCI sits between the upper and lower layers of the BLE protocol stack. Everything from L2CAP upward runs in software on the host. Everything from the Link Layer downward runs in firmware on the controller. HCI is the bridge between them.

Figure 9.1 — HCI Position in the LE Protocol Stack

GATT-Based Profiles
Generic Access Profile (GAP)
Generic Attribute Profile (GATT)
Security Manager (SM)
Attribute Protocol (ATT)
L2CAP

← runs on HOST (application CPU)

Host Controller Interface (HCI)
← UART / USB / SDIO / SPI physical transport →

Link Layer
Bluetooth Radio (Physical Layer)

← runs on CONTROLLER (Bluetooth chip)

Three Advantages of Reusing the HCI from BR/EDR

Rather than designing a completely new HCI for BLE, the specification reused the existing HCI from classic BR/EDR Bluetooth and extended it with LE-specific commands and events. This decision had three major benefits for developers and manufacturers:

1
Code Reuse — Save Months of Development

All the code already written to handle the HCI layer in BR/EDR implementations can be used directly with LE. The routines that transmit commands, receive events, transmit data packets, and receive data packets are completely identical. Only the new LE-specific command and event opcodes need to be added on top. A developer who has already built a BR/EDR Bluetooth host stack gets BLE HCI support with a fraction of the work.

2
Backward Compatibility — Replace Without Rewriting

A controller that supports dual mode (both BR/EDR and BLE) is fully backward compatible with the BR/EDR controller it replaces. Any product that was working with a BR/EDR-only chip can have that chip swapped for a dual mode chip without breaking any existing BR/EDR functionality. The host software does not need to be modified for the BR/EDR side at all.

3
Zero Software Changes for Dual Mode Upgrade

When a product upgrades from a BR/EDR-only controller to a dual mode controller, absolutely no software changes are needed for the existing BR/EDR functionality. The existing driver, command handling, and event processing code all continue to work exactly as before. Only new code to handle the LE-specific commands and events needs to be added.

9.1.1 — HCI Packet Types

Three Types of Packets — One Absent in LE

Three types of packets travel across the HCI interface. Two are used exactly as in BR/EDR. One is slightly modified for LE. One BR/EDR packet type is absent entirely from LE.

📤

HCI Command Packet

Host → Controller. Format is identical to BR/EDR. Only the OGF value and specific OCF opcodes differ for LE commands.

📥

HCI Event Packet

Controller → Host. Slightly enhanced for LE — all LE events use a single new event code (LE Meta Event = 0x3E) with a sub-event code inside.

📦

HCI ACL Data Packet

Bidirectional. Format is identical to BR/EDR. All L2CAP data for LE connections travels in these packets.

🚫

SCO/eSCO Packets

Not supported in LE. SCO was designed for synchronous voice audio in BR/EDR. LE has no equivalent and does not need it.

9.1.2 — HCI Command Packet Format

16-bit OpCode, OGF and OCF Fields — How LE Uses OGF 0x08

Every HCI command has a 16-bit OpCode that identifies which command it is. The OpCode is split into two sub-fields: the upper 6 bits form the OGF (Opcode Group Field) and the lower 10 bits form the OCF (Opcode Command Field).

The OGF groups commands by category. For all BLE-specific commands, the OGF is always 0x08. This is how the controller knows whether an incoming command is a BR/EDR command or an LE command — it checks the OGF first.

Figure 9.2 — HCI Command Packet Format

Bit 08162432

OCF
10 bits
[9:0]
OGF
6 bits
[15:10]
LE = 0x08
Param Len
8 bits
Parameters
Variable length
(0 to 255 bytes)

OpCode field breakdown — 16 bits total:
bits [15:10] = OGF (6 bits)
+
bits [9:0] = OCF (10 bits)
=
16-bit OpCode
OGF 0x01 = Link Control (BR/EDR disconnect, inquiry)
OGF 0x03 = Controller/Baseband (reset, set event mask)
OGF 0x08 = LE Controller (ALL BLE commands)
OGF 0x04 = Informational Parameters (read version)
/* Sending a raw HCI command with BlueZ hcitool */
/* Format: hcitool cmd OGF OCF [parameters...]  */

/* Example: LE Set Advertise Enable             */
/* OGF=0x08, OCF=0x000A, param: 0x01=enable     */
hcitool cmd 0x08 0x000a 01

/* Example: LE Set Scan Enable                  */
/* OGF=0x08, OCF=0x000C, params: enable, filter */
hcitool cmd 0x08 0x000c 01 00

/* Programmatic: building an HCI command in C   */
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

/* Every LE command uses OGF_LE_CTL = 0x08      */
/* OCF values are defined in hci.h as            */
/* OCF_LE_SET_ADVERTISE_ENABLE  = 0x000A        */
/* OCF_LE_SET_SCAN_ENABLE       = 0x000C        */
/* OCF_LE_CREATE_CONN           = 0x000D        */
/* OCF_LE_SET_ADVERTISING_DATA  = 0x0008        */

9.1.3 — HCI Event Packet — The LE Meta Event

All LE Events Fit Under One Umbrella — Code 0x3E

In BR/EDR, each different event type has its own unique event code. If you wanted to catch a “Connection Complete” event you would look for event code 0x03. If you wanted “Inquiry Complete” it would be event code 0x01. Every event had its own code in a flat namespace.

For BLE, rather than consuming many new event codes in that same namespace, the specification reserved a single event code 0x3E — the LE Meta Event — and put all LE events inside it. Inside the LE Meta Event, a Subevent Code identifies exactly which LE event occurred. The remaining bytes after the subevent code are the event-specific parameters.

Figure 9.3 — HCI Event Packet Formats (BR/EDR vs LE Meta Event)

Standard BR/EDR Event Packet:
Event Code
1 byte
Total Length
1 byte
Event Parameters…
Variable

LE Meta Event Packet — ALL LE events use this wrapper:
Event Code
= 0x3E
Total Length
1 byte
Subevent Code
1 byte
IDs the LE event
Subevent Parameters
Depends on subevent
Subevent code 0x01 = LE Connection Complete, 0x02 = LE Advertising Report, 0x03 = LE Connection Update Complete, etc.
/* Catching LE Meta Events in BlueZ C code                    */
/* All LE events share event code HCI_LE_META_EVENT = 0x3E   */

#define HCI_LE_META_EVENT  0x3e

/* Subevent codes (defined in hci.h):                         */
#define EVT_LE_CONN_COMPLETE          0x01  /* Connection done  */
#define EVT_LE_ADVERTISING_REPORT     0x02  /* ADV packet seen  */
#define EVT_LE_CONN_UPDATE_COMPLETE   0x03  /* Params updated   */
#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
#define EVT_LE_LTK_REQUEST            0x05  /* Key needed       */

/* Parsing an HCI event in a filter loop:                     */
hci_filter_set_event(HCI_LE_META_EVENT, &filter);
read(hci_sock, &buf, sizeof(buf));

evt_le_meta_event *meta = (void *)(buf + HCI_EVENT_HDR_SIZE + 1);
switch (meta->subevent) {
    case EVT_LE_CONN_COMPLETE:
        printf("LE connection established\n");
        break;
    case EVT_LE_ADVERTISING_REPORT:
        printf("LE advertising report received\n");
        break;
}

9.1.4 — HCI ACL Data Packet

Same Format as BR/EDR — L2CAP Data Flows Through Here

ACL (Asynchronous Connection-Less) data packets carry the actual application data between host and controller. The format for LE is identical to BR/EDR — the same field structure, the same connection handle field, and the same Packet Boundary (PB) and Broadcast (BC) flag bits.

All the data that flows between the L2CAP layer on the host and the link layer on the controller travels in these ACL packets. GATT notifications, ATT reads and writes, Security Manager pairing messages — all of it goes through HCI ACL packets.

Figure 9.4 — HCI ACL Data Packet
Handle
12 bits
Connection handle
PB
2 bits
Packet Boundary
BC
2 bits
Broadcast
Data Length
16 bits
Bytes of data
Data
Variable
L2CAP payload
PB bits: 00=first L2CAP fragment, 01=continuing fragment, 10=complete (no fragmentation). BC: always 00 for LE (no broadcast connections).

9.2 — Table 9.1 — All LE-Related HCI Commands and Events

Naming Convention — How to Read the Command Names

Before looking at the table, here is the naming logic:

HCI_LE_*

Commands that are only for LE. These do not exist in BR/EDR and are always rejected by a BR/EDR-only controller.

HCI_*

Commands shared by both BR/EDR and LE. These work the same way on both types of controller, though their meaning may expand slightly with LE.

LE_*

Events specific to LE only. Events without the LE prefix apply to both BR/EDR and LE controllers.

Commands and events introduced in specs 4.1 and 4.2 are shown in italics in the original textbook’s Table 9.1. In the table below they are highlighted in colour.

Table 9.1 — LE Related HCI Commands and Events (Complete)

Group Commands Events
Device Setup HCI_Reset
Controller Flow Control HCI_Read_Buffer_Size
HCI_LE_Read_Buffer_Size
Number_Of_Completed_Packets_Event
Host Flow Control HCI_Host_Buffer_Size
HCI_Set_Event_Mask
HCI_Set_Controller_To_Host_Flow_Control
HCI_Host_Number_Of_Completed_Packets
HCI_LE_Set_Event_Mask
HCI_LE_Add_Device_To_White_List
HCI_LE_Clear_White_List
HCI_LE_Read_White_List_Size
HCI_LE_Remove_Device_From_White_List
HCI_LE_Add_Device_To_Resolving_List
HCI_LE_Remove_Device_From_Resolving_List
HCI_LE_Clear_Resolving_List
HCI_LE_Read_Resolving_List_Size
HCI_LE_Read_Peer_Resolvable_Address
HCI_LE_Read_Local_Resolvable_Address
HCI_LE_Set_Address_Resolution_Enable
Data_Buffer_Overflow_Event
Controller Information HCI_Read_Local_Version_Information
HCI_Read_Local_Supported_Commands
HCI_Read_Local_Supported_Features
HCI_LE_Read_Local_Supported_Features
HCI_LE_Read_Supported_States
HCI_LE_Read_Maximum_Data_Length
Remote Information HCI_Read_Remote_Version_Information
HCI_LE_Read_Remote_Used_Features
Read_Remote_Version_Information_Complete
LE_Read_Remote_Used_Features_Complete
Controller Configuration HCI_LE_Set_Advertise_Enable
HCI_LE_Set_Advertising_Data
HCI_LE_Set_Advertising_Parameters
HCI_LE_Set_Random_Address
HCI_LE_Set_Scan_Response_Data
HCI_Read_LE_Host_Support
HCI_Write_LE_Host_Support
HCI_LE_Set_Resolvable_Private_Address_Timeout
Device Discovery HCI_LE_Set_Scan_Enable
HCI_LE_Set_Scan_Parameters
LE_Advertising_Report_Event
LE_Direct_Advertising_Report_Event
Connection Setup HCI_Disconnect
HCI_LE_Create_Connection_Cancel
HCI_LE_Create_Connection
Disconnect_Complete_Event
LE_Connection_Complete_Event
LE_Enhanced_Connection_Complete_Event
HCI_* = shared with BR/EDR
HCI_LE_* = LE only
Green text = introduced in BLE 4.1 or 4.2
/* Quick reference — most commonly used LE HCI commands */

/* Start advertising: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, 1_byte);

/* Start scanning: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, ...);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, 2_bytes);

/* Create a connection: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_CREATE_CONN, ...);
/* Wait for LE_Connection_Complete meta event (subevent 0x01) */

/* Disconnect: */
hci_send_cmd(sock, OGF_LINK_CTL, OCF_DISCONNECT, 3_bytes);
/* Wait for Disconnect_Complete event */

/* Check controller capabilities: */
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_READ_LOCAL_SUPPORTED_FEATURES, 0);
hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_READ_SUPPORTED_STATES, 0);

Chapter 9 Introduced — HCI Commands Reference Complete

You now understand the HCI layer fully — where it sits, why it was reused from BR/EDR, all three packet types, and the complete command table. The next chapters go deeper into specific command groups and how the host uses them to drive device discovery, connection setup, and data transfer.

Leave a Reply

Your email address will not be published. Required fields are marked *