杰理 SDK 文档中心
首页
首页
  • 项目概览

    • SDK 简介与核心特性
    • 芯片平台与硬件资料
    • SDK 版本与发布信息
  • 快速开始

    • 环境搭建与工具链
    • 编译工程
    • 烧录与量产工具
  • 工程结构与构建系统

    • 工程目录布局
    • 构建与链接配置
  • 应用层开发

    • mbox_flash 应用框架
    • 板级支持包 (BSP)
    • 公共应用模块
    • UI 显示子系统
  • 蓝牙子系统

    • BLE 控制器、链路层与 HCI 传输
    • GATT 服务框架
    • BLE 应用示例:遥控器 / Dongle / 对讲机
    • 经典蓝牙支持
  • 音频子系统

    • 音频编解码器
    • 音频设备接口 (DAC / ADC / APA)
    • 音效处理与 EQ
    • 播放、录音与 MIO 工作流
  • 设备与文件系统

    • 存储设备驱动 (NorFlash / SDMMC / USB)
    • 文件系统 (FAT / nor_fs / SYDF)
    • 设备管理框架 (dev_mg)
  • 系统服务与电源管理

    • 消息机制 (msg / hot_msg)
    • 配置与参数存储 (app_config / VM)
    • 电源管理 (SOFT OFF / POWER DOWN)
  • 固件升级

    • 升级框架总览 (code_v1 / code_v2)
    • 双 Bank 升级机制
    • 升级通道:UART / 测试盒 / BLE OTA / USB / SD
  • 补丁包与版本维护

    • 版本升级补丁链 (v1.1.0 → v1.4.0)
    • 问题修复补丁
    • 固件裁剪与资源优化
  • 开发工具与支持

    • 辅助工具与脚本
    • 文档、配置说明与常见问题

BLE 控制器、链路层与 HCI 传输

AW30N BLE SDK 中负责蓝牙低功耗(BLE)协议栈底层的完整实现面:HCI(Host Controller Interface)传输抽象层、BLE 链路层(Link Layer)控制器 API,以及它们与上层 Host 之间的命令/事件/数据通路。

Purpose and Scope

本文档面向需要理解或扩展 AW30N BLE 协议栈底层的工程师,系统性地说明三部分内容:

  1. HCI 传输层(hci_transport.h):UART(H4/H5/eHCILL)与 USB 等物理传输通道的抽象接口,用于连接外部蓝牙 Host(如 PC、手机 SoC 上的 Host 协议栈)。
  2. 链路层控制器 API(ble/hci_ll.h):Vendor Host 直接调用 Controller 的 LL 部分 API,覆盖广播、扫描、连接、加密、BLE 5.x 扩展广播、周期性广播以及 LE Audio 的 CIS/BIG/ISO 通路。
  3. 底层数据包与事件结构:ACL/ISO 数据包格式、广播报告事件、LL 事件枚举与回调注册机制。

以下内容属于其他目录页的边界,本文不展开:经典蓝牙(BR/EDR)的 hci_lmp.h 接口、GAP/GATT 等 Host 层 Profile、应用层业务(如音频链路 audio_link)。HCI 传输层虽是 Host 与 Controller 的公共边界,本文仅以 BLE 侧视角说明其接口与用法。

Overview

BLE 协议栈在逻辑上分为 Host(主机)与 Controller(控制器)两大部分,二者之间通过 HCI(Host Controller Interface)划分:

  • Controller:包含物理层(PHY)、链路层(LL),负责射频收发、事件调度、加密、连接状态机等实时性要求极高的任务。
  • Host:包含 L2CAP、SM、GAP、GATT 等逻辑层,负责协议语义与上层应用交互。
  • HCI:定义命令(Command)、事件(Event)、ACL 数据、ISO 数据与 SCO 数据五类分组,是 Host 控制 Controller 的唯一标准接口。

AW30N 是单芯片方案,因此 SDK 提供两条路径同时支持两种部署形态:

  1. 片内 Vendor Host 直连:应用代码通过 hci_ll.h 暴露的 ll_hci_* API 直接驱动 Controller 的链路层,省去标准 HCI 命令解析开销。这也是 SDK 默认、推荐的方式。
  2. 外部 Host 经传输层连接:通过 hci_transport.h 的 UART(H4/H5)或 USB 传输实例,把本芯片当作纯 Controller 使用,由外部 Host 协议栈通过 HCI 分组控制。

hci_ll.h 的头部注释明确说明了这一点:"提供Vendor Host 直接调用Controller API LL Part",即把 HCI 层最核心的 LL 命令子集以 C 函数形式直接暴露给片内 Host。

// hci_ll.h 头部:明确本头文件的定位
//   Filename        : hci_ll.h
//   Description     : 提供Vendor Host 直接调用Controller API LL Part

Source: hci_ll.h

Architecture

下图展示 AW30N 中 BLE 控制器、链路层与 HCI 传输的整体架构及两条 Host 通路:

flowchart TD
    subgraph sg_Host["Host 层(片上 / 外部)"]
        App["应用 / GAP / GATT 等 Host 逻辑"]
        VHost["Vendor Host(片上直连)"]
        ExtHost["外部 Host(PC / 手机 SoC)"]
    end

    subgraph sg_LL_API["链路层 API 面(ble/hci_ll.h)"]
        LLHostAPI["ll_hci_* Host 侧 API<br/>adv / scan / conn / security"]
        LLCtrlAPI["ll_hci_cmd_handler / ll_event_handler<br/>Controller 侧接口"]
        LLBle5["BLE 5.x / ISO 扩展 API<br/>ext adv / periodic adv / CIS / BIG"]
    end

    subgraph sg_HCI_Transport["HCI 传输抽象层(hci_transport.h)"]
        H4["hci_transport_h4_instance"]
        H5["hci_transport_h5_instance<br/>BCSP / 自动休眠"]
        UART["btstack_uart_block_*<br/>POSIX / FreeRTOS / embedded"]
        USB["hci_transport_usb_instance"]
    end

    subgraph sg_Controller["Controller(PHY + Link Layer)"]
        LL["Link Layer 状态机"]
        BB["基带 / 事件调度<br/>bb_le_timer_* / bb_le_clk_get_time_us"]
        RF["射频 PHY"]
    end

    App -->|"ll_hci_* 直连调用"| VHost
    VHost --> LLHostAPI
    LLHostAPI --> LLCtrlAPI
    LLCtrlAPI --> LL
    LLBle5 --> LLCtrlAPI
    LL --> BB
    BB --> RF
    ExtHost -->|"HCI 分组(H4/H5/USB)"| H4
    ExtHost --> H5
    ExtHost --> USB
    H4 --> UART
    H5 --> UART
    UART -->|"字节流"| LLCtrlAPI
    USB -->|"USB 传输"| LLCtrlAPI
    LL -.->|"事件 / ACL / ISO 数据"| LLHostAPI

架构要点说明:

  • 两条 Host 通路互斥或并存:片上应用通常走 ll_hci_* 直连路径(左侧),外部 Host 则通过 HCI 传输层(右侧)以标准 HCI 分组与 Controller 交互。两类接口最终都汇聚到 Controller 侧的统一入口 ll_hci_cmd_handler(int *cmd) 与事件出口 ll_event_handler(int *msg)。
  • 传输层是可插拔的:hci_transport_t 是一个函数指针结构体,H4、H5、USB 分别是其不同实现;btstack_uart_block_t 进一步抽象了底层 UART 驱动(POSIX/FreeRTOS/嵌入式),使同一套 HCI 逻辑可跨平台运行。
  • 链路层 API 面按能力分层:基础 LE 能力(广播/扫描/连接/加密)为 ll_hci_* 直接函数;BLE 5.x 与 LE Audio(CIS/BIG/ISO)因为参数为变长结构,统一采用 (u8 *data, u32 size) 形式的二进制参数接口。
  • 时间关键路径下沉到 BB 层:链路层依赖 bb_le_timer_set/get/reset/register/del 与 bb_le_clk_get_time_us 获取微秒级时钟,保证连接事件与广播事件的时间精度。

Source: hci_ll.h、hci_transport.h

HCI 传输层:hci_transport.h 详解

hci_transport.h 定义了两个层次的抽象:UART 驱动接口(btstack_uart_block_t)与 HCI 传输实例接口(hci_transport_t)。这种分层借鉴了 BTstack 的设计:传输实例负责 HCI 分组级语义(帧头、分片、流控),UART 驱动只负责字节级收发,二者通过函数指针注入,可在编译期或运行期组合。

UART 配置与休眠模式

传输启动前需要给出 UART 参数。btstack_uart_config_t 包含波特率、流控开关与设备名三个字段,是所有 UART 实现的统一配置入口:

typedef struct {
    uint32_t   baudrate;
    int        flowcontrol;
    const char *device_name;
} btstack_uart_config_t;

Source: hci_transport.h

休眠模式枚举定义了三种 UART 省电策略,是低功耗设计的关键:

枚举值含义适用协议
BTSTACK_UART_SLEEP_OFFUART 常开,无省电默认
BTSTACK_UART_SLEEP_RTS_HIGH_WAKE_ON_CTS_PULSERTS 拉高,CTS 脉冲唤醒eHCILL(TI H4 扩展)
BTSTACK_UART_SLEEP_RTS_LOW_WAKE_ON_RX_EDGERTS 拉低,RX 边沿唤醒H5 及不支持 CTS 脉冲唤醒的 eHCILL
typedef enum {
    // UART active, sleep off
    BTSTACK_UART_SLEEP_OFF = 0,
    // used for eHCILL
    BTSTACK_UART_SLEEP_RTS_HIGH_WAKE_ON_CTS_PULSE,
    // used for H5 and for eHCILL without support for wake on CTS pulse
    BTSTACK_UART_SLEEP_RTS_LOW_WAKE_ON_RX_EDGE,
} btstack_uart_sleep_mode_t;

Source: hci_transport.h

设计意图:BLE 外设(如 TWS 耳机、穿戴设备)对功耗极其敏感,HCI UART 在空闲时必须能关闭时钟。eHCILL 用 CTS 脉冲做确定性唤醒(字节不会丢),H5 则退化为 RX 边沿唤醒(唤醒瞬间的字节可能丢失,需要 H5 重传机制兜底)。

UART 驱动接口:btstack_uart_block_t

btstack_uart_block_t 是纯函数指针结构体,相当于一个"块式"(block-oriented)UART 驱动契约:

typedef struct {
    int (*init)(const btstack_uart_config_t *uart_config);
    int (*open)(void);
    int (*close)(void);
    void (*set_block_received)(void (*block_handler)(void));
    void (*set_block_sent)(void (*block_handler)(void));
    int (*set_baudrate)(uint32_t baudrate);
    int (*set_parity)(int parity);
    int (*set_flowcontrol)(int flowcontrol);
    void (*receive_block)(uint8_t *buffer, uint16_t len);
    void (*send_block)(const uint8_t *buffer, uint16_t length);
    int (*get_supported_sleep_modes)(void);
    void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode);
    void (*set_wakeup_handler)(void (*wakeup_handler)(void));
} btstack_uart_block_t;

Source: hci_transport.h

关键语义:

  • receive_block / send_block 是非阻塞的块传输:调用方给出缓冲区和长度,完成或出错通过 set_block_received / set_block_sent 注册的回调通知。这使得 HCI 传输层可以运行在中断驱动、无轮询的异步模型下。
  • set_sleep / set_wakeup_handler 是低功耗扩展点:set_wakeup_handler 注册的回调会在 CTS 脉冲或 RX 数据到来时被调用,用于通知 HCI 传输层"Controller 请求唤醒"(见头文件第 116-119 行注释)。
  • SDK 提供四个公共实现工厂:btstack_uart_block_posix_instance()、btstack_uart_block_windows_instance()、btstack_uart_block_embedded_instance()、btstack_uart_block_freertos_instance(),分别面向 PC 调试、嵌入式裸机与 FreeRTOS 环境。

HCI 传输实例接口:hci_transport_t

hci_transport_t 封装了 HCI 分组级能力:注册分组回调、发送分组、查询是否可立即发送等:

typedef struct {
    const char *name;
    void (*init)(const void *transport_config);
    int (*open)(void);
    int (*close)(void);
    void (*register_packet_handler)(void (*handler)(int packet_type, const u8 *packet, int size));
    int (*can_send_packet_now)(uint8_t packet_type);
    int (*send_packet)(int packet_type, const u8 *packet, int size);
    int (*set_baudrate)(uint32_t baudrate);
    void (*reset_link)(void);          // H5/BCSP 链路复位
    void (*set_sco_config)(uint16_t voice_setting, int num_connections); // USB SCO 配置
} hci_transport_t;

Source: hci_transport.h

设计要点:

  • register_packet_handler 是 HCI 数据上行入口,回调参数 packet_type 区分命令/事件/ACL/SCO/ISO 分组。
  • can_send_packet_now 支持"异步传输层"(无缓冲、中断驱动)——发送前先查询是否可发,避免阻塞。
  • reset_link 是 H5(BCSP)特有扩展,用于复位 H5 链路层状态机;set_sco_config 是 USB 传输的扩展,用于配置 SCO 连接数。这两个扩展以可选函数指针形式存在,体现了接口设计的"最小公共接口 + 按需扩展"思路。

传输配置与实例工厂

配置类型用 type 字段区分 UART 与 USB 两种传输,便于在统一入口上做类型分派:

typedef enum {
    HCI_TRANSPORT_CONFIG_UART,
    HCI_TRANSPORT_CONFIG_USB
} hci_transport_config_type_t;

typedef struct {
    hci_transport_config_type_t type; // == HCI_TRANSPORT_CONFIG_UART
    uint32_t   baudrate_init; // initial baud rate
    uint32_t   baudrate_main; // = 0: same as initial baudrate
    int        flowcontrol;
    const char *device_name;
} hci_transport_config_uart_t;

Source: hci_transport.h

baudrate_init 与 baudrate_main 分离的用意:H4/H5 协议支持"波特率切换"——先用低速波特率完成 HCI 命令交换,再通过命令把双方切到高速波特率,baudrate_main 为 0 时表示与初始波特率相同。

实例工厂函数一览:

工厂函数用途
hci_transport_h4_instance(uart_driver)H4 协议(单字节分组指示 + CRC 可选),需传入 btstack_uart_block_t
hci_transport_h5_instance(uart_driver)H5 协议(面向字节流的三线 UART,含滑动窗口重传),需传入 btstack_uart_block_t
hci_transport_usb_instance()USB 传输实例
hci_transport_uart_instance()通用 UART 传输
hci_transport_h4_controller_instance()Controller 侧 H4 实例
hci_transport_h4_host_instance()Host 侧 H4 实例

配套的 H5 控制函数:hci_transport_h5_set_auto_sleep(inactivity_timeout_ms) 设置空闲休眠超时(0 为关闭),hci_transport_h5_enable_bcsp_mode() 开启 BCSP 模式(启用事件奇偶校验),hci_transport_usb_set_path(len, port_numbers) 按 USB 端口路径指定设备。

链路层 API:hci_ll.h 详解

hci_ll.h 是片上 Host 与链路层之间的"零拷贝"接口面。与标准 HCI 不同,这里没有命令解析器与命令完成事件的往返,而是把 LL 功能直接映射为 C 函数调用,降低延迟与 RAM 开销。文件内注释把 API 明确划分为 Host part 与 Controller part 两大块,外加 BLE 5.x 扩展与厂商(vendor)扩展。

Host 侧 API:广播 / 扫描 / 连接 / 加密

这部分函数由片内 Host 直接调用,是应用层最常接触的 LL 入口:

//Adjust Host part API
void ll_hci_init(void);
void ll_hci_reset(void);
void ll_hci_destory(void);

void ll_hci_set_event_mask(const u8 *mask);
void ll_hci_set_name(const char *name);

void ll_hci_adv_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
                           uint8_t direct_address_type, uint8_t *direct_address,
                           uint8_t channel_map, uint8_t filter_policy);
void ll_hci_adv_set_data(uint8_t advertising_data_length, uint8_t *advertising_data);
void ll_hci_adv_scan_response_set_data(uint8_t scan_response_data_length, uint8_t *scan_response_data);
int ll_hci_adv_enable(bool enable);

void ll_hci_scan_set_params(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window);
int ll_hci_scan_enable(bool enable, u8 filter_duplicates);

int ll_hci_create_conn(u8 *conn_param, u8 *addr_param);
int ll_hci_create_conn_ext(void *param);
int ll_hci_create_conn_cancel(void);

Source: hci_ll.h

接口设计规律:

  • 生命周期:ll_hci_init → 配置(广播/扫描参数)→ 使能(*_enable)→ 使用 → ll_hci_reset/ll_hci_destory。init 与 reset 分离,便于运行中恢复出厂链路状态而不释放资源。
  • 参数语义对齐 HCI 规范:ll_hci_adv_set_params 的参数顺序与 HCI LE Set Advertising Parameters 命令一致(间隔、类型、直连地址、信道图、过滤策略),从标准 Host 移植代码成本低。
  • 返回 int 表示成否:使能类接口返回 0 成功、非 0 失败,失败原因通常映射到 Controller 错误码(如 CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16)。

连接与加密相关的函数覆盖了 LE 安全的核心流程:

int ll_hci_encryption(u8 *key, u8 *plaintext_data);       // AES-128 加密原语
int ll_hci_get_le_rand(void);                              // 获取随机数
int ll_hci_start_encryption(u16 handle, u32 rand_low, u32 rand_high, u16 peer_ediv, u8 *ltk);
int ll_hci_long_term_key_request_reply(u16 handle, u8 *ltk);        // 应答 LTK 请求
int ll_hci_long_term_key_request_nagative_reply(u16 handle);        // 拒绝 LTK 请求
int ll_hci_connection_update(u16 handle, u16 conn_interval_min, u16 conn_interval_max,
                             u16 conn_latency, u16 supervision_timeout,
                             u16 minimum_ce_length, u16 maximum_ce_length);
u16 ll_hci_get_acl_data_len(void);
u16 ll_hci_get_acl_total_num(void);
void ll_hci_set_random_address(u8 *addr);
int ll_hci_disconnect(u16 handle, u8 reason);
int ll_hci_read_local_p256_pb_key(void);
int ll_hci_generate_dhkey(const u8 *data, u32 size);

Source: hci_ll.h

其中 ll_hci_start_encryption 对应 HCI LE Start Encryption(传入 EDIV 与 Rand 的低/高 32 位),ll_hci_connection_update 对应 LE Connection Update,ll_hci_generate_dhkey 对应 SMP 的 P-256 DH 密钥生成——这些是 LE Secure Connections 的底层支撑。

Controller 侧 API:命令入口与事件出口

Controller 侧接口是双通路汇聚点:无论命令来自片内 Host 直连还是外部 HCI 传输,最终都进入 ll_hci_cmd_handler 解析执行;事件与数据则通过 ll_event_handler 向上分发。

//Adjust Controller part API
void ll_hci_cmd_handler(int *cmd);   // HCI 命令统一入口(含标准命令与 vendor 命令)
void ll_event_handler(int *msg);     // LL 事件向上分发
void ll_hci_private_free_dma_rx(u8 *rx_head);  // 释放 DMA RX 缓冲
void ll_hci_set_data_length(u16 conn_handle, u16 tx_octets, u16 tx_time);  // LE Data Length
hci_ll_param_t *ll_hci_param_config_get(void); // 读取地址类型/过滤策略位域配置
void hci_ll_get_device_address(uint8_t *addr_type, u8 *addr);
void ll_hci_set_host_channel_classification(u8 *channel_map); // 主机信道分类

Source: hci_ll.h

hci_ll_param_t 是一个 8 位位域结构,集中了四种地址/过滤策略配置,避免为每个策略单开接口:

typedef struct {
    u8 Own_Address_Type: 2;
    u8 Adv_Filter_Policy: 2;
    u8 Scan_Filter_Policy: 2;
    u8 initiator_filter_policy: 2;
} hci_ll_param_t;

Source: hci_ll.h

ll_hci_private_free_dma_rx 的存在说明 RX 路径使用 DMA 直接写入内存,上层处理完数据后需显式归还缓冲——这是典型的零拷贝设计,也是内存管理上必须配对使用的约束(使用后不释放会导致 RX 缓冲耗尽)。

BLE 5.x 扩展:扩展广播 / 周期性广播 / PHY

BLE 5 的命令参数复杂且长度可变,因此 API 风格统一为"二进制参数 + 长度",由调用方按 hci_ll.h 中定义的打包结构填充:

// ble5
void ll_hci_set_ext_adv_params(u8 *data, u32 size);
void ll_hci_set_ext_adv_data(u8 *data, u32 size);
void ll_hci_set_ext_adv_enable(u8 *data, u32 size);
void ll_hci_set_phy(u16 conn_handle, u8 all_phys, u8 tx_phy, u8 rx_phy, u16 phy_options);
void ll_hci_set_ext_scan_params(u8 *data, u32 size);
void ll_hci_set_ext_scan_enable(u8 *data, u32 size);
void ll_hci_ext_create_conn(u8 *data, u32 size);
void ll_hci_set_periodic_adv_params(u8 *data, u32 size);
void ll_hci_set_periodic_adv_data(u8 *data, u32 size);
void ll_hci_set_periodic_adv_enable(u8 *data, u32 size);
void ll_hci_periodic_adv_creat_sync(u8 *data, u32 size);
void ll_hci_periodic_adv_terminate_sync(u8 *data, u32 size);
void ll_hci_periodic_adv_create_sync_cancel(void);

Source: hci_ll.h

对应的参数结构体(均为 _GNU_PACKED_ 紧凑布局,直接对应 HCI 命令参数区)包括:

  • le_set_ext_adv_param_t:扩展广播参数(Advertising_Handle、Event_Properties、主/次信道 PHY、Advertising_SID 等 16 个字段)。
  • le_set_ext_adv_data_t:扩展广播数据,Advertising_Data[31] 定长数组承载最长 31 字节的载荷。
  • le_set_ext_adv_en_t:扩展广播使能(Enable、Number_of_Sets、Duration、Max_Extended_Advertising_Events)。
  • __ext_scan_param / __ext_scan_enable:扩展扫描参数(可含多 PHY 的 scan_phy_param[] 变长数组)与使能(Filter_Duplicates、Duration、Period)。
  • le_evt_type_t:扩展广播事件类型的位域联合体,用 16 bit 位域描述 Connectable/Scannable/Directed/Scan_response/Legacy/Data_status,并可通过 event_type 字段整体读写。
/*! \brief      LE Extended Advertising report event. */
typedef union {
    struct {
        uint16_t Connectable_advertising    : 1,
                 Scannable_advertising      : 1,
                 Directed_advertising       : 1,
                 Scan_response              : 1,
                 Legacy_adv_PDUs_used       : 1,
                 Data_status                : 2,
                 All_other_bits             : 9;
    };
    uint16_t event_type;
} _GNU_PACKED_ le_evt_type_t;

Source: hci_ll.h

LE Audio(ISO)扩展:CIS / CIG / BIG

hci_ll.h 为 LE Audio(LE 2M/CODED PHY 上的 ISO 数据)提供了完整的数据结构与命令接口,覆盖 CIG/CIS(连接等时流)与 BIG/BIS(广播等时流)两条通路:

void ll_hci_set_cig_params(uint8_t *data, size_t size);
void ll_hci_create_cis(uint8_t *data, size_t size);
void ll_hci_remove_cig(uint8_t *data, size_t size);
void ll_hci_accept_cis_req(uint8_t *data, size_t size);
void ll_hci_create_big(uint8_t *data, size_t size);
void ll_hci_big_create_sync(uint8_t *data, size_t size);
void ll_hci_big_terminate_sync(uint8_t *data, size_t size);
void ll_hci_read_iso_tx_sync(uint8_t *data, size_t size);
void ll_hci_setup_iso_data_path(uint8_t *data, size_t size);

Source: hci_ll.h

关键数据结构:

  • le_set_cig_param_t:CIG 参数(SDU_Interval、Packing、Framing、Max_Transport_Latency、CIS_Count 及变长 param[] 数组,每个 CIS 含 PHY/RTN/Max_SDU)。
  • le_create_cis_t:创建 CIS,param[] 为 CIS 连接句柄与 ACL 连接句柄对。
  • le_create_big_t:创建 BIG,含 Broadcast_Code[16] 加密密钥、RTN、PHY、Packing/Framing 等。
  • le_big_create_sync_t / le_big_terminate_sync_t:接收端同步/终止 BIG。
  • hci_iso_data_packets_t / hci_iso_hdr_t:ISO 数据分组头,位域包含 Connection_Handle(12)、PB_Flag(2)、TS_Flag(1)、ISO_Data_Load_Length(14),以及时间戳、Packet_Sequence_Num、ISO_SDU_Length、Packet_Status_Flag(2)(0b00 有效 / 0b01 可能错误 / 0b10 数据丢失)。

hci_iso_hdr_t 对 pb_flag 的注释给出了分片语义(0b00 首片、0b01 续片、0b10 完整 SDU、0b11 末片),packet_status_flag 则让接收方知道 SDU 是否完整——这对音频数据是"丢包不重传、但必须告知解码器"场景的关键设计。

LL 事件与回调注册机制

链路层向上报事件有两种通道:一是 ll_event_handler(int *msg) 的 LL 内部事件(枚举 LL_EVENT_SUPERVISION_TIMEOUT、LL_EVENT_RX、LL_EVENT_ACL_TX_POST),二是面向 Host 的回调注册接口:

enum {
    LL_EVENT_SUPERVISION_TIMEOUT,
    LL_EVENT_RX,
    LL_EVENT_ACL_TX_POST,
};

void hci_add_event_handler(void *callback_handler);
void hci_remove_event_handler(void *callback_handler);
void ll_hci_event_callback_register(void (*callback)(uint8_t packet_type, uint8_t *packet, uint16_t size));
void hci_iso_receive_callback_register(void *callback);
void ll_conn_rx_acl_callback_register(void (*callback)(uint8_t *packet, size_t size));
void ll_big_tx_align_callback_register(uint8_t big_handle, const void *callback);
void ll_cig_tx_align_callback_register(uint8_t cig_id, const void *callback);

Source: hci_ll.h、hci_ll.h

回调语义分析:

  • hci_add_event_handler / hci_remove_event_handler 是通用事件分发器,支持注册/注销多个处理器,用于 HCI 事件(如连接完成、加密变化)。
  • ll_hci_event_callback_register 是分组级回调(packet_type + packet + size),与 HCI 传输层的 register_packet_handler 签名一致,说明片内 Host 与外部 Host 看到的是同一类事件流。
  • ll_conn_rx_acl_callback_register 直接暴露 ACL 接收数据包;ll_big_tx_align_callback_register / ll_cig_tx_align_callback_register 用于 CIG/BIG 发送对齐——LE Audio 要求音频数据按等时间隔(ISO_Interval)对齐发送,回调在时间点到达时触发应用填充音频帧。
  • 事件头中的 hci_iso_receive_callback_register 注册 ISO 数据接收回调,配合 ll_iso_unpack_hdr 解包 ISO 头:
uint8_t ll_iso_unpack_hdr(const uint8_t *sdu, hci_iso_hdr_t *hdr);

基带定时器与时钟接口

链路层的时间关键操作依赖 BB 层提供的微秒级定时器,这些接口也被暴露给上层用于调试与同步:

typedef void (*timeout_callback_t)(void *priv);
void bb_le_timer_set(uint8_t idx, uint32_t usec, timeout_callback_t callback, void *priv);
u32 bb_le_clk_get_time_us(void);
uint8_t bb_le_timer_get(void);
void bb_le_timer_reset(uint8_t idx, uint32_t usec);
void bb_le_timer_register(uint8_t idx, timeout_callback_t callback, void *priv);
void bb_le_timer_del(uint8_t idx);

Source: hci_ll.h

bb_le_clk_get_time_us 返回链路层 1/12 微秒精度的系统时钟(ll_get_ctrler_clk 的输出参数 us_1per12 印证了这一点),定时器以索引(idx)管理、支持 set/reset/register/del 完整生命周期。事件调度(连接事件、广播事件、CIG/BIG 对齐)都建立在它之上。

核心流程

流程一:片内 Vendor Host 直连链路层(广播示例)

以"开启广播"为例,展示从应用调用到射频发射的完整控制流:

sequenceDiagram
    participant App as 应用层
    participant LL as ll_hci_* API(hci_ll.h)
    participant Cmd as ll_hci_cmd_handler
    participant LLState as Link Layer 状态机
    participant BB as 基带(bb_le_timer_*)
    participant RF as 射频 PHY

    App->>LL: ll_hci_adv_set_params(间隔, 类型, 信道图, 过滤策略)
    LL->>Cmd: 参数打包为 LL 命令
    Cmd->>LLState: 配置广播参数
    App->>LL: ll_hci_adv_set_data(len, advertising_data)
    LL->>Cmd: 设置广播数据
    App->>LL: ll_hci_adv_enable(true)
    LL->>Cmd: 使能广播
    Cmd->>LLState: 进入 Advertising 状态
    LLState->>BB: 注册广播事件定时器(bb_le_timer_set)
    BB->>RF: 按 adv_interval 触发 PDU 发送
    RF-->>LLState: TX 完成
    LLState->>Cmd: 上报事件(ll_event_handler / 回调)
    Cmd-->>App: hci_add_event_handler 注册的回调

流程要点: 参数设置是同步的(void 返回,直接写入链路层状态),只有使能类操作返回 int 表达结果;射频发送由 BB 定时器驱动,与 CPU 主流程异步——这也是为什么上层必须通过回调而非轮询获取发送结果。

流程二:外部 Host 经 HCI UART 传输(H4)控制 Controller

当 AW30N 作为纯 Controller 被外部 Host 驱动时,HCI 分组流经传输层:

sequenceDiagram
    participant Host as 外部 Host
    participant T as hci_transport_h4_instance
    participant U as btstack_uart_block_*(UART 驱动)
    participant Cmd as ll_hci_cmd_handler
    participant Evt as ll_event_handler / 回调

    Host->>T: send_packet(HCI_CMD, cmd, size)
    T->>T: 添加 H4 分组指示字节(0x01 命令)
    T->>U: send_block(buffer, len)
    U->>Cmd: UART 中断接收 → DMA → 命令缓冲
    Cmd->>Cmd: 解析并执行 LL 命令
    Cmd->>Evt: 生成 Command Complete / LE Meta 事件
    Evt->>T: register_packet_handler 分发事件分组
    T->>U: send_block(事件分组)
    U-->>Host: 事件经 UART 返回

流程要点: 外部 Host 路径与片内直连路径共享 ll_hci_cmd_handler,区别仅在命令来源(UART 分组 vs 直接函数调用)。can_send_packet_now 在发送前查询 UART 是否可写,避免在无缓冲传输层上阻塞。

流程三:LE Audio 发送对齐(CIG/BIG)

ISO 数据对时序敏感,发送对齐回调是设计核心:

sequenceDiagram
    participant App as 音频应用
    participant Cb as ll_cig_tx_align_callback_register 回调
    participant LL as 链路层(ISO 调度)
    participant BB as 基带时钟

    App->>Cb: 注册 CIG 发送对齐回调
    BB->>LL: ISO_Interval 时间点到达(bb_le_clk_get_time_us 校准)
    LL->>Cb: 触发对齐回调
    Cb->>App: 填充音频 SDU 到 ISO 缓冲
    App->>LL: 提交 ISO SDU(hci_iso_hdr_t 描述)
    LL->>BB: 按 CIG 参数(NSE/BN/PHY)发送
    BB-->>App: 发送完成(packet_status_flag 反馈状态)

使用示例

示例一:初始化并配置广播

以下代码展示片内 Host 使用 hci_ll.h API 的典型调用序列(参数结构取自头文件声明):

// 生命周期初始化
ll_hci_init();
ll_hci_set_event_mask(mask);
ll_hci_set_name("AW30N_DEV");

// 配置广播:间隔 100ms~100ms,ADV_IND,全信道
ll_hci_adv_set_params(160, 160, 0 /*ADV_IND*/,
                      0 /*public*/, NULL,
                      0x07 /*37/38/39 信道*/, 0 /*过滤策略*/);

// 设置广播数据(31 字节以内)
uint8_t adv_data[] = { 0x02, 0x01, 0x06, 0x03, 0x03, 0x12, 0x18, 0x00 };
ll_hci_adv_set_data(sizeof(adv_data), adv_data);
ll_hci_adv_scan_response_set_data(0, NULL);

// 使能广播
int ret = ll_hci_adv_enable(true);

Source: hci_ll.h

示例二:建立连接与加密

连接建立与 LTK 应答的典型序列:

// 主动连接:conn_param 为连接参数,addr_param 为目标地址
int ret = ll_hci_create_conn(conn_param, addr_param);

// 收到对端加密请求后,用 LTK 应答
int ok = ll_hci_long_term_key_request_reply(handle, ltk);
// 或者拒绝
int no = ll_hci_long_term_key_request_nagative_reply(handle);

// 发起连接参数更新
ll_hci_connection_update(handle, 6, 6, 0, 500, 0xFFFF, 0xFFFF);

// 断开连接(原因码见 Controller Error Codes,如 0x16)
ll_hci_disconnect(handle, CONNECTION_TERMINATED_BY_LOCAL_HOST);

Source: hci_ll.h

示例三:HCI 传输层初始化(外部 Host / H4 + FreeRTOS UART)

传输层组合示例——用 FreeRTOS UART 驱动构造 H4 传输实例:

// 1. 选择 UART 驱动实现(FreeRTOS / POSIX / embedded / windows)
const btstack_uart_block_t *uart_driver = btstack_uart_block_freertos_instance();

// 2. 构造 H4 传输实例
const hci_transport_t *transport = hci_transport_h4_instance(uart_driver);

// 3. UART 配置:初始波特率 115200,主波特率 1000000,使能流控
hci_transport_config_uart_t config = {
    .type = HCI_TRANSPORT_CONFIG_UART,
    .baudrate_init = 115200,
    .baudrate_main = 1000000,
    .flowcontrol = 1,
    .device_name = "bt_uart",
};

// 4. 初始化并注册 HCI 分组回调
transport->init(&config);
transport->register_packet_handler(hci_packet_handler);
transport->open();

// 5. 发送 HCI 命令分组(packet_type 为 HCI_COMMAND_PACKET)
transport->send_packet(HCI_COMMAND_PACKET, cmd_buf, cmd_len);

Source: hci_transport.h、hci_transport.h

配置选项

以下配置项来自 HCI 传输层与链路层 API 面,均以结构体字段或函数参数形式暴露:

配置项类型默认/取值说明
btstack_uart_config_t.baudrateuint32_t由调用方指定UART 初始波特率
btstack_uart_config_t.flowcontrolint由调用方指定硬件流控开关(RTS/CTS)
btstack_uart_config_t.device_nameconst char*由调用方指定设备节点名(如 "bt_uart")
hci_transport_config_uart_t.baudrate_inituint32_t115200 常见初始波特率,用于 HCI 握手
hci_transport_config_uart_t.baudrate_mainuint32_t0(=init)切换后的主波特率
btstack_uart_sleep_mode_tenumSLEEP_OFFUART 休眠模式:OFF / eHCILL(CTS 脉冲) / H5(RX 边沿)
hci_transport_h5_set_auto_sleepuint16_t0(关闭)H5 空闲休眠超时(ms)
hci_transport_h5_enable_bcsp_modevoid关闭启用 BCSP 模式(事件奇偶校验)
ll_hci_adv_set_params 参数多类型调用方指定广播间隔/类型/信道图/过滤策略
ll_hci_adv_set_data 长度uint8_t≤31广播数据长度
ll_hci_set_data_lengthuint16_t调用方指定LE Data Length 的 tx_octets/tx_time
ll_set_scan_priorityuint8_t调用方指定扫描优先级
hci_ll_param_t 位域4×2bit调用方指定Own 地址类型、广播/扫描/发起过滤策略

API 参考

以下为 hci_ll.h 与 hci_transport.h 中最重要的公开接口签名。完整列表以头文件为准,此处按功能分组给出核心条目。

生命周期与初始化

函数说明
void ll_hci_init(void)初始化链路层 Host 接口,必须先于其他 ll_hci_* 调用
void ll_hci_reset(void)复位链路层状态(连接、广播、扫描全部终止)
void ll_hci_destory(void)销毁链路层 Host 接口,释放资源
void ll_hci_set_event_mask(const u8 *mask)设置事件掩码,控制哪些 HCI 事件上报
void ll_hci_set_name(const char *name)设置设备名(用于 Read Local Name)

广播与扫描

函数说明
void ll_hci_adv_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type, uint8_t direct_address_type, uint8_t *direct_address, uint8_t channel_map, uint8_t filter_policy)配置广播参数;间隔单位为 0.625ms
void ll_hci_adv_set_data(uint8_t advertising_data_length, uint8_t *advertising_data)设置广播数据(≤31 字节)
void ll_hci_adv_scan_response_set_data(uint8_t len, uint8_t *data)设置扫描响应数据
int ll_hci_adv_enable(bool enable)使能/关闭广播;返回 0 成功
void ll_hci_scan_set_params(uint8_t scan_type, uint16_t scan_interval, uint16_t scan_window)配置扫描参数
int ll_hci_scan_enable(bool enable, u8 filter_duplicates)使能/关闭扫描,可同时开启重复过滤
void ll_hci_set_random_address(u8 *addr)设置随机地址(用于隐私)

连接与安全

函数说明
int ll_hci_create_conn(u8 *conn_param, u8 *addr_param)发起 LE 连接
int ll_hci_create_conn_ext(void *param)发起扩展连接(BLE 5)
int ll_hci_create_conn_cancel(void)取消未完成的连接请求
int ll_hci_disconnect(u16 handle, u8 reason)断开连接,reason 为 HCI 错误码
int ll_hci_start_encryption(u16 handle, u32 rand_low, u32 rand_high, u16 peer_ediv, u8 *ltk)启动链路加密
int ll_hci_long_term_key_request_reply(u16 handle, u8 *ltk)应答 LTK 请求(接受)
int ll_hci_long_term_key_request_nagative_reply(u16 handle)应答 LTK 请求(拒绝)
int ll_hci_connection_update(u16 handle, u16 interval_min, u16 interval_max, u16 latency, u16 timeout, u16 ce_min, u16 ce_max)更新连接参数
int ll_hci_read_local_p256_pb_key(void) / int ll_hci_generate_dhkey(const u8 *data, u32 size)LE Secure Connections:读本地 P-256 公钥 / 计算 DH 密钥

事件与回调

函数说明
void hci_add_event_handler(void *callback_handler)注册 HCI 事件处理器(可多个)
void hci_remove_event_handler(void *callback_handler)注销事件处理器
void ll_hci_event_callback_register(void (*cb)(uint8_t packet_type, uint8_t *packet, uint16_t size))注册分组级事件回调
void ll_conn_rx_acl_callback_register(void (*cb)(uint8_t *packet, size_t size))注册 ACL 接收回调
void hci_iso_receive_callback_register(void *callback)注册 ISO 数据接收回调
void ll_cig_tx_align_callback_register(uint8_t cig_id, const void *callback)注册 CIG 发送对齐回调
void ll_big_tx_align_callback_register(uint8_t big_handle, const void *callback)注册 BIG 发送对齐回调

HCI 传输层

函数说明
const hci_transport_t *hci_transport_h4_instance(const btstack_uart_block_t *uart_driver)构造 H4 传输实例
const hci_transport_t *hci_transport_h5_instance(const btstack_uart_block_t *uart_driver)构造 H5 传输实例
const hci_transport_t *hci_transport_usb_instance(void)构造 USB 传输实例
const hci_transport_t *hci_transport_h4_controller_instance(void)Controller 侧 H4 实例
const hci_transport_t *hci_transport_h4_host_instance(void)Host 侧 H4 实例
void hci_transport_h5_set_auto_sleep(uint16_t inactivity_timeout_ms)设置 H5 自动休眠超时(0 关闭)
void hci_transport_h5_enable_bcsp_mode(void)启用 BCSP 模式
void hci_transport_usb_set_path(int len, uint8_t *port_numbers)按 USB 端口路径选择设备
const btstack_uart_block_t *btstack_uart_block_freertos_instance(void) 等 4 个获取平台 UART 驱动实例

传输接口方法(hci_transport_t 函数指针):

  • init(const void *transport_config):初始化传输,transport_config 为 hci_transport_config_uart_t 或 USB 配置。
  • open() / close():打开/关闭传输连接。
  • register_packet_handler(handler):注册 HCI 分组回调(packet_type + packet + size)。
  • can_send_packet_now(packet_type):查询是否可立即发送指定类型分组。
  • send_packet(packet_type, packet, size):发送分组;返回 0 成功,非 0 失败(如缓冲区满)。
  • set_baudrate(baudrate):运行期切换波特率(H4/H5 波特率切换用)。
  • reset_link():H5/BCSP 链路复位。
  • set_sco_config(voice_setting, num_connections):USB 传输配置 SCO。

故障模式、边界情况与并发

连接超时与断开

  • 链路层通过 LL_EVENT_SUPERVISION_TIMEOUT 事件上报监督超时(连接参数中的 supervision_timeout 到期且未收到任何有效包)。上层应通过 ll_hci_disconnect 或直接处理该事件完成状态清理。
  • 主动断开原因码 CONNECTION_TERMINATED_BY_LOCAL_HOST (0x16) 在 hci_ll.h 中以宏定义暴露,表明 SDK 内部按 HCI 规范错误码体系组织断开原因。

DMA 缓冲生命周期

  • RX 数据经 DMA 直接写入内存(ll_hci_private_free_dma_rx(u8 *rx_head) 的存在证明此设计)。上层处理完 RX 数据后必须调用该函数归还缓冲,否则 DMA RX 缓冲池耗尽将导致接收停止。这是零拷贝设计伴随的显式内存管理约束。

回调注册的并发语义

  • hci_add_event_handler / hci_remove_event_handler 支持多处理器,但头文件未声明线程安全语义。在 FreeRTOS/裸机场景下,事件回调运行在链路层上下文(中断或高优先级任务),回调内不得执行阻塞操作(如等待互斥锁、长时间打印),否则将直接拉长链路层调度周期,造成连接事件漂移。
  • set_block_received / set_block_sent 的回调同样是中断上下文,处理必须轻量;真正耗时的解析应推迟到任务上下文。

休眠模式的字节丢失风险

  • BTSTACK_UART_SLEEP_RTS_LOW_WAKE_ON_RX_EDGE(H5)模式下,唤醒瞬间 RX 上的字节可能丢失,依赖 H5 滑动窗口重传机制恢复;而 eHCILL 的 CTS 脉冲唤醒是确定性的。选择休眠模式时必须与所用协议(H4 无重传 vs H5 有重传)匹配,否则会引入不可恢复的帧错误。

参数边界

  • ll_hci_adv_set_data 的广播数据长度以 uint8_t 传递,标准广播通道 PDU 上限 31 字节;扩展广播数据(le_set_ext_adv_data_t)为 31 字节定长数组,而 le_set_prd_adv_data_t 注释标注"0 to 252"字节——不同接口的容量上限不同,超限填充会造成 PDU 截断或参数错误。
  • ll_hci_create_conn 失败返回非 0 后,必须调用 ll_hci_create_conn_cancel 或等待连接超时清理内部状态机,不能直接重发。

性能与运行考虑

零拷贝与 DMA

  • 链路层 RX 使用 DMA 直写(ll_hci_private_free_dma_rx),TX 方向数据包结构均为 _GNU_PACKED_ 紧凑布局,与 HCI 规范逐字节对应,避免了结构体填充导致的协议偏差。

时间精度

  • bb_le_clk_get_time_us() 与 ll_get_ctrler_clk(hdl, &us_1per12, &ref_clk_us, &evt) 提供微秒级时间基准,连接事件、广播事件、CIG/BIG 发送对齐全部依赖它。任何上层对链路层时间的占用(长临界区、关中断)都会直接影响射频调度精度。

带宽估算工具

  • hci_ll.h 尾部提供三个带宽估算函数,用于在启动连接/广播前评估 PHY 与载荷长度下的空中时间开销:
uint32_t ll_aux_ind_packet_bandwidth(uint8_t phy, uint16_t payload_len, uint8_t encrypt);
uint32_t ll_ext_ind_packet_bandwidth(uint8_t phy, uint16_t payload_len, uint8_t encrypt);
uint32_t ll_padv_packet_bandwidth(uint8_t phy, uint16_t payload_len, uint8_t encrypt);

Source: hci_ll.h

  • 配合 ll_vendor_latency_hold_cnt(conn_handle, hold_cnt)、ll_vendor_open_latency / ll_vendor_close_latency 等厂商延迟控制接口,可以在功耗与吞吐之间做运行期权衡。

功耗控制

  • UART 休眠模式(eHCILL/H5)、H5 自动休眠超时、ll_set_scan_priority 扫描优先级、ll_hci_set_data_length 数据长度限制等,共同构成低功耗调优的手段。默认全关(SLEEP_OFF、auto_sleep=0),需要功耗优化时按链路状态逐步开启。

扩展点

  • 平台 UART 驱动:实现 btstack_uart_block_t 的全部函数指针即可接入新平台(POSIX/Windows/embedded/FreeRTOS 之外的自定义驱动),H4/H5 传输逻辑无需改动。
  • 事件分发:hci_add_event_handler 支持多处理器注册,可在不侵入链路层的情况下挂接调试探针、日志或协议分析器。
  • 音频对齐回调:ll_cig_tx_align_callback_register / ll_big_tx_align_callback_register 让应用在 ISO 时间点填充音频数据,可扩展实现不同的编解码缓冲策略(如双缓冲、动态水位)。
  • Vendor 命令:ll_set_vendor_param(uint8_t *vendor_param, size_t size) 提供厂商私有参数注入通道,SDK 的专有特性(如 ll_set_private_access_addr_pair_channel、ll_vendor_set_code_type、rf_mdm_con_ble_sync_word TWS 同步)都通过这类接口扩展。
  • MAC 管理:le_controller_set_mac(void *addr) 可运行期覆盖设备地址,用于产线烧录或多地址场景。

Related Links

  • 经典蓝牙 HCI/LMP 接口(hci_lmp.h) —— 经典蓝牙侧的对应接口,本文未展开
  • hci_transport.h 完整头文件
  • hci_ll.h 完整头文件
  • 补丁包中同一接口的版本差异:补丁包/v1.2.0升级至v1.3.0蓝牙补丁/include_lib/bt_controller_include/ble/hci_ll.h、补丁包/v1.3.4升级至v1.4.0蓝牙相关补丁/.../hci_ll.h 可供对比版本演进
Next
GATT 服务框架