BES BLE低功耗蓝牙技术实现分析

BES BLE低功耗蓝牙技术实现分析

目录

  1. BLE基础知识

  2. 广播机制与低功耗优化

  3. 连接建立流程

  4. 数据传输机制

  5. 断连处理与恢复

  6. 状态机设计

  7. 代码实现分析

  8. BLE协议层交互与时序详解

  9. 常见问题与调试

  10. 性能优化建议

  11. 硬件RF层与物理层深度解析

  12. SMP安全管理与配对鉴权

  13. 错误码体系

  14. LMP命令与扩展Opcode

    • 14.1 [LMP Opcode定义](#LMP Opcode定义)
  15. Slot时间片调度机制深度解析

  16. 总结


1. BLE基础知识

1.1 BLE协议栈层次

复制代码
┌─────────────────────────────────────┐
│      应用层 (Application)           │
├─────────────────────────────────────┤
│      GATT (Generic Attribute)       │
├─────────────────────────────────────┤
│      ATT (Attribute Protocol)       │
├─────────────────────────────────────┤
│      L2CAP (Logical Link Control)   │
├─────────────────────────────────────┤
│      HCI (Host Controller Interface)│
├─────────────────────────────────────┤
│      Link Layer (链路层)            │
├─────────────────────────────────────┤
│      Physical Layer (物理层)        │
└─────────────────────────────────────┘

1.2 BLE角色定义

  • Broadcaster (广播者): 周期性发送广播数据包
  • Observer (观察者): 扫描并接收广播数据包
  • Peripheral (外设/从设备): 可连接的设备,等待中心设备连接
  • Central (中心/主设备): 发起连接的设备

1.3 BLE地址类型详解

BLE设备支持多种地址类型以满足不同的隐私和安全需求:

地址类型 说明 应用场景
Public (公共地址) 0x00 类似MAC地址,全球唯一,由IEEE分配 固定设备、需要全球唯一标识的场景
Random Static (随机静态地址) 0x01 上电时随机生成,设备运行期间保持不变 需要持久标识但不需要全球唯一性
Private Resolvable (RPA) 0x02 使用IRK加密生成,可被授权设备解析 隐私保护、已配对设备重连
Private Non-resolvable 0x03 随机生成且不可解析 临时广播、最高隐私级别
1.3.1 地址类型枚举定义
c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:211-233
enum bes_addr_type
{
    /// Public BD address (IEEE分配的全球唯一地址)
    BES_ADDR_PUBLIC = 0x00,

    /// Random BD Address (随机地址)
    BES_ADDR_RAND,

    /// Controller generates Resolvable Private Address based on the
    /// local IRK from resolving list. If resolving list contains no matching
    /// entry, use public address.
    BES_ADDR_RPA_OR_PUBLIC,

    /// Controller generates Resolvable Private Address based on the
    /// local IRK from resolving list. If resolving list contains no matching
    /// entry, use random address.
    BES_ADDR_RPA_OR_RAND,

    /// mask used to determine Address type in the air
    BES_ADDR_MASK = 0x01,

    /// mask used to determine if an address is an RPA
    BES_ADDR_RPA_MASK = 0x02,

    /// Random device address (controller unable to resolve)
    BES_ADDR_RAND_UNRESOLVED = 0xFE,

    /// No address provided (anonymous advertisement)
    BES_ADDR_NONE = 0xFF,
};
1.3.2 Own Address Type (本地地址源类型)

设备使用的本地地址类型定义:

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:278-288
typedef enum
{
   /// Public or Private Static Address according to device address configuration
   /// 根据设备配置使用公共地址或私有静态地址
   BES_GAP_STATIC_ADDR,

   /// Generated resolvable private random address
   /// 生成可解析私有随机地址(RPA)
   BES_GAP_GEN_RSLV_ADDR,

   /// Generated non-resolvable private random address
   /// 生成不可解析私有随机地址
   BES_GAP_GEN_NON_RSLV_ADDR,
} BES_GAP_OWN_ADDR_E;
1.3.3 地址相关API

设置本地IRK (Identity Resolving Key)

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:961-965
/**
 * @brief Set local irk
 * @param[in] p_irk IRK (16字节)
 */
void bes_ble_gap_set_local_irk(const uint8_t *p_irk);

获取本地地址

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:1123-1128
/**
 * @brief Get local static ble IA addr
 * @return ble_bdaddr_t 本地Identity Address
 */
ble_bdaddr_t bes_ble_gap_get_current_ble_addr(void);

获取本地RPA地址

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:1138-1144
/**
 * @brief Get local rpa addr
 * @param[in] conidx      Conn idx
 * @return const uint8_t* RPA地址指针
 */
const uint8_t *bes_ble_gap_get_local_rpa_addr(uint8_t conidx);

通过广播handle读取RPA地址

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:1146-1151
/**
 * @brief Read local rpa addr by adv hdl--HCI cmd
 * @param[in] adv_hdl  Adv handle
 */
void bes_ble_gap_read_local_rpa_by_adv_hdl(uint8_t adv_hdl);
1.3.4 地址解析与隐私保护

RPA超时设置

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:641-649
/**
 * @brief Set the length of time the Controller uses a
 *        Resolvable Private Address before a new resolvable private
 *        address is generated and starts being used
 * @param[in] rpa_timeout  Range: 0x0001 to 0x0E10, in unit of seconds
 *                         (1秒到3600秒,默认15分钟)
 */
void bes_ble_gap_set_rpa_timeout(uint16_t rpa_timeout);

添加设备到解析列表(Resolving List)

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:629-634
/**
 * @brief Set rpa list
 * @param[in] ble_addr  BLE addr
 * @param[in] irk       IRK (Identity Resolving Key, 16字节)
 */
void bes_ble_gap_set_rpa_list(const ble_bdaddr_t *ble_addr, const uint8_t *irk);

添加已配对设备到解析列表

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:636-640
/**
 * @brief Set bonded devices of nv record to rpa list
 * 将NV记录中的已配对设备添加到RPA解析列表
 */
void bes_ble_gap_set_bonded_devs_rpa_list(void);
1.3.5 地址使用建议
场景 推荐地址类型 原因
初次配对/广播 Public 或 Random Static 设备易于识别,方便扫描发现
已配对设备重连 RPA (BES_ADDR_RPA_OR_PUBLIC) 保护隐私,防止设备被追踪
临时广播 Non-resolvable Private 最高隐私级别
固定设备(如信标) Public 需要全局唯一标识

2. 广播机制与低功耗优化

2.1 广播数据包结构

BLE广播数据包最大31字节(Legacy ADV)或255字节(Extended ADV):

复制代码
┌────────┬──────┬────────────────┐
│ Length │ Type │     Data       │
├────────┼──────┼────────────────┤
│ 1 byte │1 byte│ N bytes        │
└────────┴──────┴────────────────┘

常用广播类型(AD Type):

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:109-186
enum bes_gap_ad_type
{
    BES_GAP_AD_TYPE_FLAGS = 0x01,                      // Flags
    BES_GAP_AD_TYPE_MORE_16_BIT_UUID = 0x02,          // 部分16-bit UUID列表
    BES_GAP_AD_TYPE_COMPLETE_LIST_16_BIT_UUID = 0x03, // 完整16-bit UUID列表
    BES_GAP_AD_TYPE_MORE_128_BIT_UUID = 0x06,         // 部分128-bit UUID列表
    BES_GAP_AD_TYPE_COMPLETE_LIST_128_BIT_UUID = 0x07,// 完整128-bit UUID列表
    BES_GAP_AD_TYPE_SHORTENED_NAME = 0x08,             // 短设备名称
    BES_GAP_AD_TYPE_COMPLETE_NAME = 0x09,              // 完整设备名称
    BES_GAP_AD_TYPE_TRANSMIT_POWER = 0x0A,             // 发射功率
    BES_GAP_AD_TYPE_SERVICE_16_BIT_DATA = 0x16,        // 16-bit UUID Service Data
    BES_GAP_AD_TYPE_SERVICE_128_BIT_DATA = 0x21,       // 128-bit UUID Service Data
    BES_GAP_AD_TYPE_APPEARANCE = 0x19,                 // 外观
    BES_GAP_AD_TYPE_MANU_SPECIFIC_DATA = 0xFF,         // 厂商特定数据
};

2.1.1 BLE广播通道与频率

BLE使用2.4GHz ISM频段,定义了40个RF通道(0-39),其中3个是广播通道(Advertising Channels) ,37个是数据通道(Data Channels)

广播通道特性
c 复制代码
/// bthost/adapter/inc/ble/common/co_bt_defines.h:175-177
#define ADV_CHANNEL_37      37  // 频率: 2402 MHz
#define ADV_CHANNEL_38      38  // 频率: 2426 MHz
#define ADV_CHANNEL_39      39  // 频率: 2480 MHz
广播通道 频率(MHz) 说明
Channel 37 2402 低频段,与WiFi信道1部分重叠
Channel 38 2426 中频段,位于WiFi信道6-7之间
Channel 39 2480 高频段,与WiFi信道13-14部分重叠

通道选择策略

  • 通常同时使用全部3个广播通道以提高发现概率
  • 可以根据环境干扰情况选择性禁用某些通道
  • 广播设备依次在这3个通道上发送广播包
广播通道映射
c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:235-247
enum bes_adv_channel_map
{
    /// Byte value for advertising channel map for channel 37 enable
    BES_ADV_CHNL_37_EN = 0x01,
    /// Byte value for advertising channel map for channel 38 enable
    BES_ADV_CHNL_38_EN = 0x02,
    /// Byte value for advertising channel map for channel 39 enable
    BES_ADV_CHNL_39_EN = 0x04,
    /// Byte value for advertising channel map for channel 37, 38 and 39 enable
    BES_ADV_ALL_CHNLS_EN = 0x07,
};

使用示例

c 复制代码
// 启用所有3个广播通道(推荐)
adv_param.adv_channel_map = BES_ADV_ALL_CHNLS_EN;

// 仅启用通道37和39(跳过通道38,如遇到WiFi干扰)
adv_param.adv_channel_map = BES_ADV_CHNL_37_EN | BES_ADV_CHNL_39_EN;

2.1.2 广播Flags设置

Flags是广播数据包中的重要字段,用于指示设备的发现性和能力。

Flags位定义
c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:188-207
enum
{
    /// Limited discovery flag - AD Flag - bit mask
    /// 限时可发现模式(通常用于快速配对场景)
    BES_GAP_LE_LIM_DISCOVERABLE_FLG_BIT = 0x01,
    BES_GAP_LE_LIM_DISCOVERABLE_FLG_POS = 0,

    /// General discovery flag - AD Flag - bit mask
    /// 通用可发现模式(持续可被发现)
    BES_GAP_LE_GEN_DISCOVERABLE_FLG_BIT = 0x02,
    BES_GAP_LE_GEN_DISCOVERABLE_FLG_POS = 1,

    /// Legacy BT not supported - AD Flag - bit mask
    /// 不支持传统蓝牙BR/EDR
    BES_GAP_BR_EDR_NOT_SUPPORTED_BIT = 0x04,
    BES_GAP_BR_EDR_NOT_SUPPORTED_POS = 2,

    /// Dual mode for controller supported (BR/EDR/LE) - AD Flag - bit mask
    /// 双模控制器支持(BR/EDR和LE同时支持)
    BES_GAP_SIMUL_BR_EDR_LE_CONTROLLER_BIT = 0x08,
    BES_GAP_SIMUL_BR_EDR_LE_CONTROLLER_POS = 3,
};
Flags设置API
c 复制代码
/// bthost/service/ble_app_new/inc/app_ble.h:451
/**
 * @brief Set advertising flags
 * @param[in] adv_param        广播参数结构
 * @param[in] simu_bredr_support  是否同时支持BR/EDR
 */
void app_ble_dt_set_flags(gap_adv_param_t *adv_param, bool simu_bredr_support);

使用示例

c 复制代码
// 示例1: 纯BLE设备,通用可发现模式
gap_adv_param_t adv_param;
app_ble_dt_set_flags(&adv_param, false);
// 生成Flags: 0x06 (BLE only + General Discoverable)

// 示例2: 双模设备(支持BLE和经典蓝牙)
app_ble_dt_set_flags(&adv_param, true);
// 生成Flags: 0x1A (BR/EDR + LE + General Discoverable)

2.1.3 广播数据构建API

系统提供了多种API用于构建广播数据包,支持灵活的数据组装。

原始数据添加
c 复制代码
/// bthost/adapter/inc/adapter_service/gap_service.h:3107-3109
/**
 * @brief Add raw data to advertising buffer
 * @param[in] buf   Gap data buffer
 * @param[in] data  Raw data pointer
 * @param[in] len   Data length
 * @return bool     Success or failed
 */
bool gap_dt_add_raw_data(gap_dt_buf_t *buf, const uint8_t *data, uint16_t len);

使用场景

  • 添加自定义格式的广播数据
  • 直接插入完整的AD结构(Length + Type + Data)
  • 添加厂商特定数据

使用示例

c 复制代码
gap_dt_buf_t *adv_buf = &adv_param->adv_data;

// 添加厂商特定数据
uint8_t manu_data[] = {
    0x05,       // Length = 5 bytes
    0xFF,       // Type = Manufacturer Specific Data
    0x4C, 0x00, // Company ID (Apple = 0x004C)
    0x01, 0x02  // Manufacturer data
};
gap_dt_add_raw_data(adv_buf, manu_data, sizeof(manu_data));
添加Flags
c 复制代码
/**
 * @brief Add flags to advertising data
 * @param[in] buf           Gap data buffer
 * @param[in] flags         Flags value (e.g., GAP_FLAGS_LE_GENERAL_DISCOVERABLE_MODE)
 * @param[in] bredr_support BR/EDR support flag
 * @return bool             Success or failed
 */
bool gap_dt_add_flags(gap_dt_buf_t *buf, uint8_t flags, bool bredr_support);
添加本地名称
c 复制代码
/// bthost/service/ble_app_new/inc/app_ble.h:452
/**
 * @brief Set local name in advertising data
 * @param[in] adv_param     Advertising parameter
 * @param[in] cust_le_name  Custom LE name (NULL to use default)
 */
void app_ble_dt_set_local_name(gap_adv_param_t* adv_param, const char* cust_le_name);
添加Service UUID
c 复制代码
/**
 * @brief Add 16-bit service UUID
 * @param[in] buf      Gap data buffer
 * @param[in] uuid16   16-bit UUID value
 * @param[in] complete True for complete list, false for partial
 * @return bool        Success or failed
 */
bool gap_dt_add_service_uuid_16(gap_dt_buf_t *buf, uint16_t uuid16, bool complete);

/**
 * @brief Add 128-bit service UUID
 * @param[in] buf      Gap data buffer
 * @param[in] uuid128  128-bit UUID array (16 bytes, LSB first)
 * @param[in] complete True for complete list, false for partial
 * @return bool        Success or failed
 */
bool gap_dt_add_service_uuid_128(gap_dt_buf_t *buf, const uint8_t *uuid128, bool complete);
完整示例:构建广播数据包
c 复制代码
void build_custom_adv_data(gap_adv_param_t *adv_param)
{
    gap_dt_buf_t *adv_data = &adv_param->adv_data;

    // 1. 添加Flags (通用可发现,仅LE)
    app_ble_dt_set_flags(adv_param, false);

    // 2. 添加设备名称
    app_ble_dt_set_local_name(adv_param, "MyDevice");

    // 3. 添加16-bit Service UUID (例如: Heart Rate Service = 0x180D)
    uint16_t uuid = 0x180D;
    gap_dt_add_service_uuid_16(adv_data, uuid, true);

    // 4. 添加厂商特定数据
    uint8_t manu_data[] = {
        0x06,       // Length
        0xFF,       // Type = Manufacturer Specific Data
        0x59, 0x00, // Company ID (Nordic = 0x0059)
        0x01, 0x02, 0x03  // Custom data
    };
    gap_dt_add_raw_data(adv_data, manu_data, sizeof(manu_data));
}

2.2 充电盒定向广播实现

本系统实现了智能的快慢广播切换机制以优化功耗:

2.2.1 广播参数定义
c 复制代码
// 广播间隔定义
#define CHARGEBOX_ADV_FAST_INTERVAL_MS 30    // 快速广播:30ms
#define CHARGEBOX_ADV_SLOW_INTERVAL_MS 480   // 慢速广播:480ms
#define CHARGEBOX_ADV_FAST_DURATION_MS 10000 // 快速广播持续时间:10秒
2.2.2 广播状态机
c 复制代码
typedef enum {
    BOX_ADV_RUNNING_NONE = 0,  // 未运行
    BOX_ADV_RUNNING_FAST = 1,  // 快速广播中
    BOX_ADV_RUNNING_SLOW = 2,  // 慢速广播中
} box_adv_running_e;
2.2.3 低功耗优化策略

快慢广播切换逻辑:

复制代码
启动阶段(0-10秒)
    ↓
快速广播(30ms间隔) ──── 提高发现概率
    ↓ (10秒后)
慢速广播(480ms间隔) ──── 降低功耗
    ↓
已连接/放入盒中
    ↓
停止广播 ──────────── 最低功耗

代码实现片段 (bes_ui_ble_adv.c:251-273):

c 复制代码
void ui_ble_chargebox_start_fast_adv_10s(void)
{
    // 检查连接状态,已连接则停止广播
    if (ble_is_box_connected() || ui_is_box_get_ble_connected()) {
        ble_adv_enable(BLE_TYPE_CHARGEBOX, false);
        return;
    }

    // 检查初始化状态
    if (g_box_adv_state.adv_initialized == false) {
        g_box_adv_state.need_delay_adv = true;
        return;
    }

    // 设置为快速广播状态
    g_box_adv_state.adv_running = BOX_ADV_RUNNING_FAST;

    // 设置快速广播间隔
    ui_ble_chargebox_set_interval(CHARGEBOX_ADV_FAST_INTERVAL_MS);

    // 启动10秒定时器,到期后切换到慢速广播
    os_timer_start(g_chargebox_adv_slow_timer, CHARGEBOX_ADV_FAST_DURATION_MS);

    // 使能广播
    ble_adv_enable(BLE_TYPE_CHARGEBOX, true);
}

慢速广播切换回调 (bes_ui_ble_adv.c:233-249):

c 复制代码
static void chargebox_adv_slow_timer_cb(const void *param)
{
    // 10秒后被调用,切换到慢速广播
    if (ble_is_box_connected() || ui_is_box_get_ble_connected()) {
        ble_adv_enable(BLE_TYPE_CHARGEBOX, false);
        return;
    }

    g_box_adv_state.adv_running = BOX_ADV_RUNNING_SLOW;

    // 设置慢速广播间隔(480ms)
    ui_ble_chargebox_set_interval(CHARGEBOX_ADV_SLOW_INTERVAL_MS);

    // 刷新广播
    ble_adv_enable(BLE_TYPE_CHARGEBOX, true);
}
2.2.4 广播数据构造

充电盒广播数据格式:

复制代码
┌─────┬──────┬─────────────────────────────────┐
│ Len │ Type │           Value                 │
├─────┼──────┼─────────────────────────────────┤
│ 02  │ 01   │ 06 (LE General Discoverable)    │
│ 07  │ FF   │ MAC Address (6 bytes)           │
└─────┴──────┴─────────────────────────────────┘

代码实现 (bes_ui_ble_adv.c:170-193):

c 复制代码
static void ui_ble_adv_chargebox_build_and_write(void)
{
    uint8_t useradv[ADV_MAX_LENGTH + 1] = { 0 };
    uint8_t data_size = 0;

    // Flags字段
    useradv[data_size++] = 0x02;  // Length
    useradv[data_size++] = 0x01;  // Type: Flags
    useradv[data_size++] = LE_GENERAL_DISCOVERABLE_MODE | BR_EDR_NOT_SUPPORTED;

    // Manufacturer Specific Data
    useradv[data_size++] = 0x07;  // Length
    useradv[data_size++] = 0xFF;  // Type: Manufacturer Specific Data

    // 填充MAC地址(反序)
    for (int i = 0; i < 6; i++) {
        useradv[data_size++] = 0xFF;  // 实际为MAC地址
    }

    // 获取盒子MAC地址
    uint8_t box_mac[6];
    for(int i=0; i<6; i++){
        box_mac[i] = ui_get_para()->box_info.box_mac[5-i];
    }

    // 写入广播数据
    ble_adv_write_data(BLE_TYPE_CHARGEBOX, box_mac, NULL, 0, NULL, 0);
}

2.3 广播控制HCI命令

启动广播 (HCI: 0x2039 - LE Set Extended Advertising Enable):

复制代码
日志示例:
[TX]: 01 39 20 06 01 01 08 00 00 00
解析:
01          - HCI Command Packet
39 20       - Opcode (0x2039)
06          - Parameter Length
01          - Enable (0x01=Enable, 0x00=Disable)
01          - Number of sets
08          - Advertising Handle
00 00 00    - Duration, Max Events

设置广播参数 (HCI: 0x2036 - LE Set Extended Advertising Parameters):

c 复制代码
// app_ble.c 中的广播参数设置逻辑
gap_adv_param_t adv_param = {
    .own_addr_type = own_addr_type,           // 本地地址类型
    .connectable = true,                       // 可连接
    .scannable = false,                        // 不可扫描
    .adv_interval_min_slots = interval_min,    // 最小广播间隔
    .adv_interval_max_slots = interval_max,    // 最大广播间隔
    .peer_type = peer_addr_type,              // 对端地址类型
    .peer_addr = peer_bdaddr,                 // 对端地址
};

2.3 HCI广播指令深度解析: 01 36 20

2.3.1 HCI指令格式

HCI Command: 01 36 20 = LE Set Extended Advertising Parameters V1

这是BLE 5.0引入的扩展广播参数设置指令,用于配置扩展广播的各项参数。

完整HCI指令格式:

复制代码
HCI Command Packet Structure:
01 36 20 LL [Parameters...]
│  │  │  │  └─ 参数字段 (25+ bytes)
│  │  │  └──── Parameter Length
│  │  └─────── Opcode LSB (0x36)
│  └────────── Opcode MSB (0x20)
└───────────── HCI Command Packet Type (0x01)

Opcode分解:
0x2036 = OGF(0x08) << 10 | OCF(0x36)
│        │                   └─ OCF (Opcode Command Field) = 0x36
│        └───────────────────── OGF (Opcode Group Field) = 0x08 (LE Controller Commands)

完整指令示例 (设置30ms间隔广播):
01 36 20 19 08 13 00 30 00 30 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
│  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │  │
│  │  │  │  │  │  │  │  │  │  │  └─ Primary_Advertising_Interval_Min/Max (3 bytes each)
│  │  │  │  │  │  │  └──────────── Advertising_Event_Properties (2 bytes)
│  │  │  │  │  └─────────────────── Advertising_Handle (1 byte)
│  │  │  │  └────────────────────── Parameter Length = 0x19 (25 bytes)
│  │  │  └───────────────────────── Opcode = 0x2036
│  └──────────────────────────────── HCI Command Packet
└─────────────────────────────────── Packet Type
2.3.2 参数字段详解

参数结构 (hci_i.h:1770, BLE Core Spec 5.0 Vol 4 Part E 7.8.53):

c 复制代码
typedef struct {
    uint8_t  advertising_handle;           // [0] 广播句柄 (0x00-0xEF)
    uint16_t advertising_event_properties; // [1-2] 广播事件属性 (bitmap)
    uint8_t  primary_adv_interval_min[3];  // [3-5] 最小广播间隔 (0.625ms单位)
    uint8_t  primary_adv_interval_max[3];  // [6-8] 最大广播间隔 (0.625ms单位)
    uint8_t  primary_adv_channel_map;      // [9] 主广播信道映射 (bit0=Ch37, bit1=Ch38, bit2=Ch39)
    uint8_t  own_address_type;             // [10] 本地地址类型
    uint8_t  peer_address_type;            // [11] 对端地址类型
    uint8_t  peer_address[6];              // [12-17] 对端蓝牙地址
    uint8_t  advertising_filter_policy;    // [18] 广播过滤策略
    int8_t   advertising_tx_power;         // [19] 广播发射功率 (dBm, 0x7F=不关心)
    uint8_t  primary_adv_phy;              // [20] 主广播PHY (0x01=1M, 0x03=Coded)
    uint8_t  secondary_adv_max_skip;       // [21] 次广播最大跳过数
    uint8_t  secondary_adv_phy;            // [22] 次广播PHY
    uint8_t  advertising_sid;              // [23] 广播集ID (0x00-0x0F)
    uint8_t  scan_request_notification;    // [24] 扫描请求通知使能
} __attribute__((packed)) hci_le_set_ext_adv_params_v1_t;

关键参数解析:

  1. Advertising_Event_Properties (广播事件属性, 2 bytes):
c 复制代码
Bitmap定义 (hci_i.h:1772-1775):
┌─────────────┬──────┬─────────────────────────────┐
│  Bit        │ 值   │  说明                        │
├─────────────┼──────┼─────────────────────────────┤
│  Bit 0      │ 0x01 │ Connectable advertising     │
│  Bit 1      │ 0x02 │ Scannable advertising       │
│  Bit 2      │ 0x04 │ Directed advertising        │
│  Bit 3      │ 0x08 │ High Duty Cycle Directed    │
│  Bit 4      │ 0x10 │ Use legacy PDUs             │
│  Bit 5      │ 0x20 │ Anonymous advertising       │
│  Bit 6      │ 0x40 │ Include TxPower             │
│  Bit 7-15   │      │ Reserved (RFU)              │
└─────────────┴──────┴─────────────────────────────┘

Legacy ADV类型映射:
0x0013 (0001 0011b) = Connectable + Scannable + Legacy = ADV_IND
0x0010 (0001 0000b) = Legacy only = ADV_NONCONN_IND
0x0015 (0001 0101b) = Connectable + Directed + Legacy = ADV_DIRECT_IND
  1. Primary_Advertising_Interval (广播间隔, 3 bytes, Little-Endian):
c 复制代码
// 间隔范围: 0x000020 - 0xFFFFFF (单位: 0.625ms)
// 有效范围: 20ms (0x000020) - 10485.759375s (0xFFFFFF)

示例1: 30ms广播间隔
30ms / 0.625ms = 48 (0x0030)
HCI字节序 (小端): 30 00 00

示例2: 480ms广播间隔 (慢速广播)
480ms / 0.625ms = 768 (0x0300)
HCI字节序 (小端): 00 03 00

代码转换:
uint32_t interval_ms = 30;  // 30ms
uint32_t interval_slots = interval_ms * 1000 / 625;  // = 48 slots
uint8_t interval_bytes[3];
interval_bytes[0] = (interval_slots >> 0) & 0xFF;  // 0x30
interval_bytes[1] = (interval_slots >> 8) & 0xFF;  // 0x00
interval_bytes[2] = (interval_slots >> 16) & 0xFF; // 0x00
  1. Primary_Advertising_Channel_Map (广播信道, 1 byte):
c 复制代码
BLE广播使用3个固定信道:
┌──────┬─────────┬────────────┐
│ Bit  │ 信道     │ 频率(MHz)  │
├──────┼─────────┼────────────┤
│ Bit0 │ Ch 37   │ 2402       │
│ Bit1 │ Ch 38   │ 2426       │
│ Bit2 │ Ch 39   │ 2480       │
└──────┴─────────┴────────────┘

典型值:
0x07 (0000 0111b) = 使用全部3个信道 (推荐)
0x03 (0000 0011b) = 仅使用Ch37 + Ch38
0x01 (0000 0001b) = 仅使用Ch37 (不推荐,降低发现概率)
2.3.3 实际日志解析示例

场景1: 设置快速广播参数 (30ms间隔)

复制代码
日志原始数据:
01 36 20 19 08 13 00 30 00 30 00 07 00 00 00 00 00 00 00 00 00 00 00 00 7F 01 00 01 00 00

解析:
[00] 01          = HCI Command Packet
[01-02] 36 20   = Opcode 0x2036 (LE_SET_EXT_ADV_PARAMS_V1)
[03] 19          = Parameter Length (25 bytes)
[04] 08          = Advertising_Handle (句柄8)
[05-06] 13 00   = Event_Properties (0x0013 = Connectable + Scannable + Legacy)
[07-09] 30 00 00 = Adv_Interval_Min (0x000030 = 48 × 0.625ms = 30ms)
[10-12] 30 00 00 = Adv_Interval_Max (0x000030 = 48 × 0.625ms = 30ms)
[13] 07          = Channel_Map (Ch37 + Ch38 + Ch39)
[14] 00          = Own_Address_Type (Public)
[15] 00          = Peer_Address_Type (Public)
[16-21] 00...00 = Peer_Address (全0 = 未指定)
[22] 00          = Filter_Policy (接受所有)
[23] 7F          = Tx_Power (127 = Host不关心,由Controller决定)
[24] 01          = Primary_PHY (1M PHY)
[25] 00          = Secondary_Max_Skip (0)
[26] 01          = Secondary_PHY (1M PHY)
[27] 00          = Advertising_SID (0)
[28] 00          = Scan_Request_Notification (禁用)

对应代码 (bes_ui_ble_adv.c:201-209):
adv_param.interval_min = CHARGEBOX_ADV_FAST_INTERVAL_MS;  // 30ms
adv_param.interval_max = CHARGEBOX_ADV_FAST_INTERVAL_MS;  // 30ms
ble_adv_set_properties(BLE_TYPE_CHARGEBOX, &adv_param);

场景2: 设置慢速广播参数 (480ms间隔)

复制代码
日志原始数据:
01 36 20 19 08 13 00 00 03 00 00 03 00 07 00 00 00 00 00 00 00 00 00 00 7F 01 00 01 00 00

解析:
[07-09] 00 03 00 = Adv_Interval_Min (0x000300 = 768 × 0.625ms = 480ms)
[10-12] 00 03 00 = Adv_Interval_Max (0x000300 = 768 × 0.625ms = 480ms)

对应代码 (bes_ui_ble_adv.c:246):
ui_ble_chargebox_set_interval(CHARGEBOX_ADV_SLOW_INTERVAL_MS);  // 480ms
2.3.4 HCI响应事件

Command Complete Event:

复制代码
HCI Event Packet:
04 0E 05 01 36 20 00 XX
│  │  │  │  │  │  │  └─ Selected_Tx_Power (Controller选择的发射功率, dBm)
│  │  │  │  │  │  └──── Status (0x00 = Success)
│  │  │  │  └──────────── Opcode (0x2036)
│  │  │  └───────────────── Num_HCI_Command_Packets (可发送的命令数)
│  │  └──────────────────── Parameter Length (5 bytes)
│  └─────────────────────── Event Code (0x0E = Command Complete)
└────────────────────────── HCI Event Packet

成功示例:
04 0E 05 01 36 20 00 08
表示: 命令执行成功,Controller选择的发射功率为+8dBm
2.3.5 与Legacy广播指令对比

Legacy广播指令 (BLE 4.x): 0x2006 - LE Set Advertising Parameters

c 复制代码
// 主要区别:
┌──────────────────────┬─────────────┬──────────────────┐
│ 特性                  │ Legacy      │ Extended         │
├──────────────────────┼─────────────┼──────────────────┤
│ Opcode               │ 0x2006      │ 0x2036           │
│ 参数长度              │ 15 bytes    │ 25 bytes         │
│ 最大广播数据          │ 31 bytes    │ 255 bytes (分段) │
│ 广播间隔              │ 2 bytes     │ 3 bytes          │
│ 支持PHY               │ 1M only     │ 1M/2M/Coded      │
│ 广播集ID              │ 无          │ 支持 (SID)       │
│ 定向广播地址          │ 必须        │ 可选             │
│ 发射功率控制          │ 无          │ 支持             │
└──────────────────────┴─────────────┴──────────────────┘

向后兼容性:
- 设置Event_Properties中的"Use legacy PDUs"位 (bit 4)
- Legacy模式下,广播包格式与BLE 4.x兼容
- 本系统使用0x0013 = Legacy模式,保证与旧设备兼容
2.3.6 常见问题与调试技巧

问题1: 广播间隔不生效

复制代码
原因: 间隔值超出范围或字节序错误
检查:
1. 确保间隔值在0x000020-0xFFFFFF范围内
2. 确认使用小端序 (Little-Endian)
3. 验证min <= max

正确: 30ms → 48 slots → 0x30 00 00
错误: 30ms → 48 slots → 0x00 00 30 (大端序)

问题2: 设备无法发现

复制代码
原因: Channel_Map设置不当
检查:
1. 确保至少使用2个信道 (建议0x07 = 全部3个)
2. 检查信道是否与环境冲突 (WiFi 2.4GHz)
3. 验证Event_Properties包含Connectable或Scannable

推荐配置:
- Channel_Map = 0x07 (Ch37+38+39)
- Event_Properties = 0x0013 (ADV_IND)
- Interval = 30-100ms (快速发现) 或 100-1000ms (省电)

问题3: HCI指令返回错误码

复制代码
常见错误码:
0x12 = Invalid HCI Command Parameters (参数非法)
      → 检查参数长度、范围、格式

0x0C = Command Disallowed (命令不允许)
      → 检查广播状态,确保先禁用广播再修改参数

0x01 = Unknown HCI Command (指令不支持)
      → Controller不支持Extended Advertising,使用Legacy指令

2.8 广播控制API

系统提供了完整的广播生命周期管理API,包括启动、停止、刷新和参数设置。

2.8.1 广播启动与停止

启动广播

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:599-610
/**
 * @brief Start connectable adv with adv interval
 * @param[in] advInterval   Adv interval (ms)
 */
void bes_ble_gap_start_connectable_adv(uint16_t advInterval);

/**
 * @brief Refresh start all it's flag is enabled adv
 * 刷新并启动所有已启用标志的广播
 */
void bes_ble_gap_start_adv(void);

停止广播

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:580-584
/**
 * @brief Stop all adv
 * 停止所有广播活动
 */
void bes_ble_gap_stop_adv_all(void);

停止指定广播

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:688-693
/**
 * @brief Stop custom adv
 * @param[in] actv_user Actv user (BLE_ADV_ACTIVITY_USER_E)
 */
void bes_ble_gap_custom_adv_stop(BLE_ADV_ACTIVITY_USER_E actv_user);

强制切换广播状态

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:572-578
/**
 * @brief Set force adv enable or not
 * @param[in] user           Set user (BLE_ADV_SWITCH_USER_E)
 * @param[in] isToEnableAdv  Enable or not
 */
void bes_ble_gap_force_switch_adv(enum BLE_ADV_SWITCH_USER_E user, bool isToEnableAdv);
2.8.2 广播刷新机制

刷新广播状态

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:803-806
/**
 * @brief Refresh all enabled adv
 * @param[in] advInterval  Advertising interval (ms)
 *
 * 功能说明:
 * - 停止当前所有广播
 * - 更新广播参数
 * - 重新启动已启用的广播
 */
void bes_ble_gap_refresh_adv_state(uint16_t advInterval);

检查广播状态

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:796-801
/**
 * @brief If any adv started
 * @return true/false
 */
bool bes_ble_gap_is_in_advertising_state(void);

应用层刷新接口

c 复制代码
/// bthost/service/ble_app_new/inc/app_ble.h:470
/**
 * @brief Refresh all adv state (app layer wrapper)
 * 刷新所有广播状态
 */
void app_ble_refresh_adv_state_generic(void);

使用示例

c 复制代码
// 场景1: 更新广播间隔并刷新
void update_adv_interval(uint16_t new_interval_ms)
{
    // 检查当前是否有广播正在运行
    if (bes_ble_gap_is_in_advertising_state()) {
        // 停止并使用新间隔重启广播
        bes_ble_gap_refresh_adv_state(new_interval_ms);
    }
}

// 场景2: 从快速广播切换到慢速广播
void switch_to_slow_adv(void)
{
    const uint16_t SLOW_ADV_INTERVAL = 480; // 480ms
    bes_ble_gap_refresh_adv_state(SLOW_ADV_INTERVAL);
}

// 场景3: 动态启用/禁用广播
void control_advertising(bool enable)
{
    if (enable) {
        bes_ble_gap_start_adv(); // 启动所有已配置的广播
    } else {
        bes_ble_gap_stop_adv_all(); // 停止所有广播
    }
}
2.8.3 广播参数设置

设置广播间隔

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:780-787
/**
 * @brief Set adv interval
 * @param[in] adv_intv_user  广播间隔请求用户 (BLE_ADV_INTERVALREQ_USER_E)
 * @param[in] adv_user       广播用户 (BLE_ADV_USER_E)
 * @param[in] interval       Adv interval (ms)
 */
void bes_ble_gap_param_set_adv_interval(BLE_ADV_INTERVALREQ_USER_E adv_intv_user,
                                        BLE_ADV_USER_E adv_user,
                                        uint32_t interval);

设置广播发射功率

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:789-794
/**
 * @brief Set all adv tx pwr
 * @param[in] txpwr_dbm  Tx pwr in dbm
 */
void bes_ble_set_all_adv_txpwr(int8_t txpwr_dbm);

设置广播参数结构

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:651-656
/**
 * @brief Set adv param with user
 * @param[in] param  Adv param (BLE_ADV_PARAM_T)
 */
void bes_ble_gap_set_adv_param(BLE_ADV_PARAM_T *param, uint8_t user);

2.9 白名单与过滤策略

白名单机制允许设备仅与特定的已知设备通信,提高安全性和连接效率。

2.9.1 白名单API

设置白名单

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:612-619
/**
 * @brief Set white list
 * @param[in] user   List user (BLE_WHITE_LIST_USER_E)
 * @param[in] bdaddr Addr list (ble_bdaddr_t array)
 * @param[in] size   Addr list size
 *
 * 功能说明:
 * - 最多支持8个设备地址
 * - 可以包含Public和Random地址
 * - 与Filter Policy配合使用
 */
void bes_ble_gap_set_white_list(BLE_WHITE_LIST_USER_E user,
                                const ble_bdaddr_t *bdaddr,
                                uint8_t size);

移除白名单

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:621-626
/**
 * @brief Remove white list by user
 * @param[in] user   White list user (BLE_WHITE_LIST_USER_E)
 */
void bes_ble_gap_remove_white_list_user_item(BLE_WHITE_LIST_USER_E user);

清除白名单

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:869-873
/**
 * @brief Clear white list for user BLE_WHITE_LIST_USER_MOBILE
 * 清除移动设备的白名单
 */
void bes_ble_gap_clear_white_list_for_mobile(void);
2.9.2 广播过滤策略

广播过滤策略定义了设备如何响应扫描和连接请求。

过滤策略枚举

c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:249-261
enum bes_adv_filter_policy
{
    /// Allow both scan and connection requests from anyone
    /// 允许任何设备的扫描和连接请求
    BES_ADV_ALLOW_SCAN_ANY_CON_ANY = 0x00,

    /// Allow both scan req from White List devices only and connection req from anyone
    /// 仅允许白名单设备扫描,但允许任何设备连接
    BES_ADV_ALLOW_SCAN_WLST_CON_ANY,

    /// Allow both scan req from anyone and connection req from White List devices only
    /// 允许任何设备扫描,但仅允许白名单设备连接
    BES_ADV_ALLOW_SCAN_ANY_CON_WLST,

    /// Allow scan and connection requests from White List devices only
    /// 仅允许白名单设备扫描和连接
    BES_ADV_ALLOW_SCAN_WLST_CON_WLST,
};

使用示例

c 复制代码
// 示例1: 设置白名单并使用过滤策略
void setup_whitelist_advertising(void)
{
    // 1. 构建白名单地址列表
    ble_bdaddr_t whitelist[2];

    // 设备1: Public地址
    whitelist[0].addr_type = BES_ADDR_PUBLIC;
    memcpy(whitelist[0].addr, "\x11\x22\x33\x44\x55\x66", 6);

    // 设备2: Random地址
    whitelist[1].addr_type = BES_ADDR_RAND;
    memcpy(whitelist[1].addr, "\xAA\xBB\xCC\xDD\xEE\xFF", 6);

    // 2. 设置白名单
    bes_ble_gap_set_white_list(BLE_WHITE_LIST_USER_MOBILE, whitelist, 2);

    // 3. 配置广播参数使用白名单
    BLE_ADV_PARAM_T adv_param;
    adv_param.adv_filter_policy = BES_ADV_ALLOW_SCAN_WLST_CON_WLST;
    bes_ble_gap_set_adv_param(&adv_param, BLE_ADV_USER_0);

    // 4. 启动广播
    bes_ble_gap_start_adv();
}

// 示例2: 清除白名单
void clear_whitelist(void)
{
    bes_ble_gap_remove_white_list_user_item(BLE_WHITE_LIST_USER_MOBILE);
}
2.9.3 扫描过滤策略

扫描时也可以使用过滤策略。

扫描过滤策略

c 复制代码
/// bthost/adapter/inc/adapter_service/gap_service.h:625-640
enum gap_scanning_filter_policy
{
    /// Basic unfiltered scanning - 接受所有广播
    GAP_SCAN_FILTER_POLICY_BASIC_UNFILTERED = 0b0000,

    /// Basic filtered scanning - 仅接受白名单设备的广播
    GAP_SCAN_FILTER_POLICY_BASIC_FILTERED   = 0b0001,

    /// Extended unfiltered scanning - 接受所有广播和定向广播
    GAP_SCAN_FILTER_POLICY_EXT_UNFILTERED   = 0b0010,

    /// Extended filtered scanning - 仅接受白名单设备
    GAP_SCAN_FILTER_POLICY_EXT_FILTERED     = 0b0011,
};
2.9.4 白名单最佳实践
应用场景 推荐策略 原因
初次配对 BES_ADV_ALLOW_SCAN_ANY_CON_ANY 允许任何设备发现和连接
已配对设备重连 BES_ADV_ALLOW_SCAN_ANY_CON_WLST 允许扫描但仅允许已知设备连接
高安全场景 BES_ADV_ALLOW_SCAN_WLST_CON_WLST 仅允许白名单设备
降低功耗 使用白名单 + Resolving List 减少不必要的连接请求处理

2.10 连接发现性模式

发现性模式控制设备是否可以被其他设备发现。

广播类型
c 复制代码
/// bthost/adapter/inc/ble/gap/bes_gap_api.h:263-276
enum
{
    /// Connectable Undirected advertising - 可连接非定向广播
    BES_ADV_CONN_UNDIR = 0x00,

    /// Connectable high duty cycle directed advertising - 可连接高占空比定向广播
    BES_ADV_CONN_DIR,

    /// Discoverable undirected advertising - 可发现非定向广播
    BES_ADV_DISC_UNDIR,

    /// Non-connectable undirected advertising - 不可连接非定向广播
    BES_ADV_NONCONN_UNDIR,

    /// Connectable low duty cycle directed advertising - 可连接低占空比定向广播
    BES_ADV_CONN_DIR_LDC,
};

广播类型说明

类型 可连接 可扫描 占空比 应用场景
CONN_UNDIR - 通用外设广播
CONN_DIR 高(3.75ms) 快速重连,仅对特定设备
DISC_UNDIR - 信标广播
NONCONN_UNDIR - 单向数据广播
CONN_DIR_LDC 低(≥1s) 低功耗定向重连

3. 连接建立流程

3.1 BLE连接状态机

复制代码
┌──────────┐
│  IDLE    │ 初始状态
└────┬─────┘
     │ 开始广播
     ↓
┌──────────────┐
│ ADVERTISING  │ 广播中
└────┬─────────┘
     │ 收到连接请求
     ↓
┌──────────────┐
│ CONNECTING   │ 连接建立中
└────┬─────────┘
     │ 连接成功
     ↓
┌──────────────┐
│ CONNECTED    │ 已连接
└────┬─────────┘
     │ MTU交换
     ↓
┌──────────────┐
│ MTU_EXCHANGED│ MTU已交换
└────┬─────────┘
     │ 服务发现
     ↓
┌──────────────┐
│ ENCRYPTED    │ 已加密(可选)
└────┬─────────┘
     │ 数据传输就绪
     ↓
┌──────────────┐
│   READY      │ 就绪状态
└──────────────┘

3.2 连接建立过程

3.2.1 HCI层面的连接事件

LE Meta Event (0x3E) - Connection Complete:

复制代码
事件格式:
04 3E 13 01 00 XX XX XX XX XX XX XX XX ...
│  │  │  │  │  └─ 连接参数
│  │  │  │  └─── Status (0x00 = Success)
│  │  │  └────── Subevent Code (0x01 = Connection Complete)
│  │  └───────── Parameter Length
│  └──────────── Event Code (0x3E = LE Meta Event)
└─────────────── HCI Event Packet
3.2.2 连接参数
c 复制代码
// BLE连接参数配置 (app_ble.c:855-882)
typedef struct {
    BLE_CONN_PARAM_MODE_E mode;          // 连接模式
    uint8_t priority;                     // 优先级
    uint16_t conn_interval_min;          // 最小连接间隔(1.25ms单位)
    uint16_t conn_interval_max;          // 最大连接间隔
    uint16_t conn_slave_latency_cnt;     // 从设备延迟
} BLE_CONN_PARAM_CONFIG_T;

// 连接参数模式定义
static const BLE_CONN_PARAM_CONFIG_T ble_conn_param_config[] = {
    // 默认模式: BT空闲状态
    {BLE_CONN_PARAM_MODE_DEFAULT, PRIORITY_NORMAL, 36, 36, 0},

    // AI流传输模式
    {BLE_CONN_PARAM_MODE_AI_STREAM_ON, PRIORITY_ABOVE_NORMAL1, 16, 16, 0},

    // A2DP音乐播放模式
    {BLE_CONN_PARAM_MODE_A2DP_ON, PRIORITY_ABOVE_NORMAL0, 48, 48, 0},

    // HFP通话模式
    {BLE_CONN_PARAM_MODE_HFP_ON, PRIORITY_ABOVE_NORMAL2, 48, 48, 0},

    // OTA升级模式
    {BLE_CONN_PARAM_MODE_OTA, PRIORITY_HIGH, 12, 12, 0},

    // 空闲省电模式
    {BLE_CONN_PARAM_MODE_IDLE, PRIORITY_NORMAL, 400, 400, 0},
};

连接间隔说明:

  • 1单位 = 1.25ms
  • 36单位 = 45ms (默认)
  • 12单位 = 15ms (OTA高速)
  • 400单位 = 500ms (空闲省电)

3.3 连接建立代码流程

连接打开事件处理 (app_ble.c:1370-1389):

c 复制代码
static void app_ble_connection_opened(gap_conn_item_t *p_conn)
{
    ble_global_t *g = ble_get_global();

    // 加载GATT服务端缓存
    app_ble_check_load_server_cache(p_conn);

    // 加载GATT客户端缓存
    app_ble_check_load_client_cache(p_conn);

    // 重置连接参数模式
    app_ble_reset_conn_param_mode(p_conn->con_idx);

    // 重置MTU大小为最小值
    g->curr_mtu_size[gap_zero_based_conidx(p_conn->con_idx)] = L2CAP_LE_MIN_MTU;

    // 如果连接数达到最大值,取消所有待发起的连接
    if (app_ble_connection_count() + 1 >= BLE_CONNECTION_MAX) {
        gap_cancel_all_pend_initiating(app_is_arrive_at_max_ble_connections());
    }
}

连接事件回调 (app_ble.c:1435-1459):

c 复制代码
case GAP_CONN_EVENT_OPENED:
{
    gap_conn_param_t *opened = param.opened;
    const bt_bdaddr_t *la = &opened->conn->own_addr;
    const bt_bdaddr_t *pa = &opened->peer_addr;

    // 打印连接日志
    CO_LOG_INFO("CNNS: idx=%d role=%d hdl=%04x",
        opened->con_idx,
        opened->conn->conn_flag.is_central ? 0 : 1,
        opened->connhdl);

    // 调用连接打开处理
    app_ble_connection_opened(opened->conn);

    // 通知应用层
    cb_event.evt_type = BLE_LINK_CONNECTED_EVENT;
    cb_event.p.connect_handled.conidx = gap_zero_based_conidx(opened->con_idx);
    cb_event.p.connect_handled.connhdl = opened->connhdl;
    cb_event.p.connect_handled.peer_bdaddr.addr_type = opened->peer_type & 0x01;
    memcpy(cb_event.p.connect_handled.peer_bdaddr.addr,
           opened->peer_addr.address,
           sizeof(bt_bdaddr_t));

    app_ble_global_handle(&cb_event, NULL);

    // 刷新广播状态
    app_ble_refresh_adv_state_generic();
    break;
}

3.4 连接参数更新请求机制

BLE连接建立后,Peripheral(从设备/耳机)可以主动发起连接参数更新请求,以适应不同的应用场景需求。

3.4.1 连接参数更新协议

L2CAP信令层提供了两种连接参数更新方式:

  1. L2CAP Connection Parameter Update Request (BLE 4.0+)

    • Peripheral通过L2CAP信令通道(CID=0x0005)发送更新请求
    • Central可以接受或拒绝该请求
  2. LL Connection Update Procedure (BLE 4.1+)

    • 通过Link Layer控制PDU进行参数协商
    • 双方都可以发起更新

L2CAP连接参数更新请求格式:

c 复制代码
// L2CAP Connection Parameter Update Request (l2cap_i.h:510-513)
typedef struct {
    uint16_t conn_interval_min_1_25ms;  // 最小连接间隔 (1.25ms单位)
    uint16_t conn_interval_max_1_25ms;  // 最大连接间隔
    uint16_t max_peripheral_latency;     // 从设备延迟 (跳过的连接事件数)
    uint16_t superv_timeout_ms;          // 监督超时 (10ms单位)
} gap_conn_prefer_params_t;

// Peripheral主动发起连接参数更新
void gap_recv_l2cap_conn_param_update_req(uint16_t connhdl,
                                            uint8_t trans_id,
                                            const gap_conn_prefer_params_t *params);

// Central响应连接参数更新请求
bt_status_t l2cap_accept_le_conn_parameters(uint16_t connhdl,
                                              uint8_t trans_id,
                                              bool accept,
                                              bool send_cmd_rej);
3.4.2 连接参数更新触发场景

耳机会根据不同的应用场景主动请求切换连接参数:

场景切换触发表 (app_ble.c:855-882):

模式 连接间隔 优先级 触发场景
DEFAULT 45ms (36×1.25ms) NORMAL BT空闲状态,初始连接
AI_STREAM_ON 20ms (16×1.25ms) ABOVE_NORMAL1 AI语音助手激活
A2DP_ON 60ms (48×1.25ms) ABOVE_NORMAL0 音乐播放开始
HFP_ON 60ms (48×1.25ms) ABOVE_NORMAL2 通话开始(SCO激活)
OTA 15ms (12×1.25ms) HIGH 固件升级
IDLE 500ms (400×1.25ms) NORMAL 长时间空闲省电

连接参数更新代码实现 (app_ble.c:914-1014):

c 复制代码
void app_ble_update_conn_param_mode_of_specific_connection(
    uint8_t con_idx,
    BLE_CONN_PARAM_MODE_E mode,
    bool enable)
{
    uint8_t conidx = gap_zero_based_conidx(con_idx);
    const BLE_CONN_PARAM_CONFIG_T *pConfig = NULL;

    // 根据模式查找配置
    for (uint8_t index = 0; index < BLE_CONN_PARAM_MODE_NUM; index++) {
        if (mode == ble_conn_param_config[index].ble_conn_param_mode) {
            pConfig = &ble_conn_param_config[index];
            break;
        }
    }

    if (enable) {
        // 启用新模式,设置对应bit
        existingBleConnParamModes[conidx] |= (1 << mode);

        // 检查是否有更高优先级的模式正在运行
        for (uint8_t index = 0; index < BLE_CONN_PARAM_MODE_NUM; index++) {
            if ((1 << ble_conn_param_config[index].ble_conn_param_mode) &
                existingBleConnParamModes[conidx]) {
                if (ble_conn_param_config[index].priority > pConfig->priority) {
                    // 已有更高优先级模式,不更新参数
                    return;
                }
            }
        }
    } else {
        // 禁用模式,清除对应bit
        existingBleConnParamModes[conidx] &= ~(1 << mode);

        // 查找剩余模式中优先级最高的
        const BLE_CONN_PARAM_CONFIG_T *pHighestConfig = NULL;
        for (uint8_t index = 0; index < BLE_CONN_PARAM_MODE_NUM; index++) {
            if ((1 << ble_conn_param_config[index].ble_conn_param_mode) &
                existingBleConnParamModes[conidx]) {
                if (pHighestConfig == NULL ||
                    ble_conn_param_config[index].priority > pHighestConfig->priority) {
                    pHighestConfig = &ble_conn_param_config[index];
                }
            }
        }
        pConfig = pHighestConfig;
    }

    // 执行参数更新
    if (pConfig != NULL) {
        gap_update_params_t params;
        params.conn_interval_min_1_25ms = pConfig->conn_interval_min;
        params.conn_interval_max_1_25ms = pConfig->conn_interval_max;
        params.max_peripheral_latency = pConfig->conn_slave_latency_cnt;

        // 发起连接参数更新请求
        gap_update_le_conn_parameters(gap_zero_based_ble_conidx_as_hdl(conidx), &params);
    }
}
3.4.3 防止BT/BLE时间片冲突的保护机制

关键防护逻辑 (app_ble.c:1074-1099):

c 复制代码
static void app_ble_conn_param_update_req(gap_conn_update_req_t *update_req)
{
    bool accept = true;
    uint16_t conn_interval_min_1_25ms = update_req->params_req.conn_interval_min_1_25ms;
    uint32_t conn_interval_min_us = conn_interval_min_1_25ms * 1250;

    // ⚠️ 关键保护: 防止BLE连接间隔过短导致与BT Classic冲突
    // 如果连接间隔小于15ms,会导致BLE频繁占用时间片,
    // 影响A2DP/SCO等BR/EDR链路的稳定性
    if (conn_interval_min_us < 15000) {  // 小于15ms
        // 延迟10秒后重新评估并更新参数
        fp_update_ble_connect_param_start(gap_zero_based_conidx(update_req->con_idx));

        // 先接受当前请求,避免连接异常
        accept = true;
    }

    // 响应连接参数更新请求
    gap_update_le_conn_parameters_rsp(update_req->con_idx,
                                        &update_req->params_req,
                                        accept);
}

// 延迟更新定时器回调
static void fp_update_ble_connect_param_timer_handler(void const *param)
{
    if (delay_update_conidx != GAP_INVALID_CONIDX) {
        // 检查是否有SCO通话正在进行
        if (amgr_is_bluetooth_sco_on()) {
            // SCO激活时,强制使用HFP_ON模式(60ms间隔)
            app_ble_update_conn_param_mode_of_specific_connection(
                delay_update_conidx, BLE_CONN_PARAM_MODE_HFP_ON, true);
        } else {
            // SCO未激活,恢复到默认模式(45ms间隔)
            app_ble_update_conn_param_mode_of_specific_connection(
                delay_update_conidx, BLE_CONN_PARAM_MODE_DEFAULT, true);
        }
        delay_update_conidx = GAP_INVALID_CONIDX;
    }
}

防冲突机制总结:

  1. 连接间隔下限保护: 拒绝小于15ms的BLE连接间隔请求
  2. SCO自动避让: 检测到SCO激活时,自动延长BLE连接间隔至60ms
  3. 优先级仲裁: SCO (实时语音) > A2DP (音频流) > BLE (数据传输)
  4. 延迟评估: 使用10秒定时器延迟参数更新,避免频繁切换
3.4.4 HCI层连接参数更新事件

LE Connection Update Complete Event (HCI Event 0x3E Subevent 0x03):

复制代码
事件格式:
04 3E 0A 03 00 XX XX YY YY ZZ ZZ WW WW
│  │  │  │  │  │  │  │  │  │  │  │  │
│  │  │  │  │  │  │  │  │  │  │  │  └─ Supervision Timeout (10ms单位)
│  │  │  │  │  │  │  │  │  │  └──────── Peripheral Latency
│  │  │  │  │  │  │  │  └───────────── Connection Interval (1.25ms单位)
│  │  │  │  │  │  └──────────────────── Connection Handle
│  │  │  │  │  └───────────────────────── Status (0x00=成功)
│  │  │  │  └──────────────────────────── Subevent Code (0x03)
│  │  │  └─────────────────────────────── Parameter Length
│  │  └────────────────────────────────── Event Code (0x3E=LE Meta Event)
│  └───────────────────────────────────── HCI Event Packet
└──────────────────────────────────────── Packet Type

示例:
04 3E 0A 03 00 40 00 30 00 00 00 C8 00
表示:
- Connection Handle: 0x0040
- Interval: 0x0030 (48 × 1.25ms = 60ms)
- Latency: 0x0000 (0个连接事件)
- Timeout: 0x00C8 (200 × 10ms = 2000ms)

日志示例 (R_COM4_time_data@01-20_15-49-45.log):

复制代码
# 连接建立,初始参数: 45ms间隔
[BLE] Connection Complete: interval=36 (45ms)

# 音乐开始播放,切换到A2DP_ON模式
[BLE] Update conn param: mode=A2DP_ON, interval=48 (60ms)

# 接听电话,SCO激活,切换到HFP_ON模式
[SCO] SCO connected, codec=mSBC
[BLE] Update conn param: mode=HFP_ON, interval=48 (60ms), priority=HIGH

# 通话结束,SCO断开,恢复到A2DP_ON模式
[SCO] SCO disconnected
[BLE] Update conn param: mode=A2DP_ON, interval=48 (60ms)

4. 数据传输机制

4.1 GATT协议概述

GATT (Generic Attribute Profile) 是BLE数据传输的核心协议,定义了服务和特征值的层次结构。

4.1.1 GATT协议栈
复制代码
┌─────────────────────────────────┐
│      应用层 (Application)       │
├─────────────────────────────────┤
│      GATT (服务发现与数据交互)  │
├─────────────────────────────────┤
│      ATT (属性协议)             │
├─────────────────────────────────┤
│      L2CAP (逻辑链路控制)       │
├─────────────────────────────────┤
│      HCI/LL (链路层)            │
└─────────────────────────────────┘
4.1.2 GATT over BR/EDR

GATT over BR/EDR 允许在经典蓝牙(BR/EDR)连接上使用BLE的GATT服务,实现双模设备的无缝数据传输。

特性

  • 使用L2CAP信道承载ATT协议
  • 固定L2CAP PSM = 0x001F (ATT)
  • MTU协商机制与BLE相同
  • 支持所有GATT服务和特征值

启用条件

c 复制代码
/// bthost/adapter/inc/adapter_service/gatt_service.h
// 定义了GATT over BR/EDR相关功能
// 需要编译时启用 BLE_GATT_OVER_BR/EDR 宏

应用场景

场景 说明
双模设备数据同步 BR/EDR连接传输大文件,BLE连接传输控制命令
音频设备配置 使用BR/EDR传输音频,通过GATT传输配置参数
向后兼容 支持仅有BR/EDR的老设备访问GATT服务

连接建立流程

复制代码
BR/EDR连接建立
    ↓
L2CAP连接到PSM 0x001F
    ↓
ATT层初始化
    ↓
MTU交换
    ↓
GATT服务可用

4.2 GATT服务架构

GATT定义了BLE数据传输的服务和特征值结构:

复制代码
Service (服务)
  └── Characteristic (特征值)
        ├── Value (值)
        ├── Descriptor (描述符)
        │     ├── CCCD (客户端特征配置描述符)
        │     └── CUDD (用户自定义描述符)
        └── Properties (属性)
              ├── Read
              ├── Write
              ├── Notify
              └── Indicate

4.2 数据路径服务定义

本系统实现了自定义的Datapath Service用于双向数据传输:

4.2.1 服务UUID定义
c 复制代码
// ble_datapath_server.c:34-36
// 128-bit Service UUID
#define datapath_service_uuid_128_le \
    0x12,0x34,0x56,0x78,0x90,0x00,0x00,0x80, \
    0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x01

// TX Characteristic UUID (用于发送通知)
#define datapath_tx_character_uuid_128_le \
    0x12,0x34,0x56,0x78,0x91,0x00,0x00,0x80, \
    0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x02

// RX Characteristic UUID (用于接收写入)
#define datapath_rx_character_uuid_128_le \
    0x12,0x34,0x56,0x78,0x92,0x00,0x00,0x80, \
    0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x03
4.2.2 GATT服务声明
c 复制代码
// ble_datapath_server.c:42-79
GATT_DECL_128_LE_PRI_SERVICE(g_ble_datapath_service,
    datapath_service_uuid_128_le);

// RX特征值 - 接收数据(支持写入)
GATT_DECL_128_LE_CHAR(g_ble_datapath_rx_character,
    datapath_rx_character_uuid_128_le,
    GATT_WR_REQ|GATT_WR_CMD|GATT_RD_REQ,  // 支持读写
    ATT_SEC_NONE);

GATT_DECL_CUDD_DESCRIPTOR(g_ble_datapath_rx_cudd,
    ATT_SEC_NONE);

// TX特征值 - 发送数据(支持通知)
GATT_DECL_128_LE_CHAR(g_ble_datapath_tx_character,
    datapath_tx_character_uuid_128_le,
    GATT_NTF_PROP,  // 支持通知
    ATT_SEC_NONE);

GATT_DECL_CCCD_DESCRIPTOR(g_ble_datapath_tx_cccd,
    ATT_WR_ENC);  // CCCD需要加密写入

GATT_DECL_CUDD_DESCRIPTOR(g_ble_datapath_tx_cudd,
    ATT_SEC_NONE);

4.3 MTU (Maximum Transmission Unit) 交换

MTU决定了单次传输的最大数据量:

c 复制代码
// 默认最小MTU
#define L2CAP_LE_MIN_MTU 23

// MTU交换事件处理 (app_ble.c:1523-1542)
case GAP_CONN_EVENT_MTU_EXCHANGED:
{
    gap_conn_mtu_exchanged_t *p = param.mtu_exchanged;

    CO_LOG_INFO("MTU Exchanged: conidx=%d mtu=%d",
        p->con_idx, p->mtu);

    // 更新MTU大小
    g->curr_mtu_size[gap_zero_based_conidx(p->con_idx)] = p->mtu;

    // 通知应用层
    cb_event.evt_type = BLE_MTU_EXECHANGE_EVENT;
    cb_event.p.mtu_exec_handled.conidx = gap_zero_based_conidx(p->con_idx);
    cb_event.p.mtu_exec_handled.mtu = p->mtu;

    app_ble_global_handle(&cb_event, NULL);
    break;
}

MTU对数据传输的影响:

  • MTU = 23: 每次最多传输 20字节 (23 - 3字节ATT头)
  • MTU = 247: 每次最多传输 244字节
  • MTU = 517: 每次最多传输 514字节 (最大值)

4.4 数据接收流程

4.4.1 GATT写入事件处理
c 复制代码
// ble_datapath_server.c:404-417
case GATT_SERV_EVENT_CHAR_WRITE:
{
    gatt_server_char_write_t *p = param.char_write;

    // 验证写入参数
    if (p->value_offset != 0 || p->value_len == 0 || p->value == NULL) {
        return false;
    }

    // 调用数据接收处理
    app_datapath_server_rx_data_received(svc->con_idx, svc->connhdl,
                                          p->value, p->value_len);

    // 异步发送写入响应
    bt_thread_call_func_3(gatts_send_defer_write_rsp,
                          bt_fixed_param(svc->connhdl),
                          bt_fixed_param(p->ctx->token),
                          bt_fixed_param(0));
    return true;
}
4.4.2 数据接收回调
c 复制代码
// ble_datapath_server.c:353-383
static void app_datapath_server_rx_data_received(uint8_t con_idx,
                                                   uint16_t connhdl,
                                                   const uint8_t *data,
                                                   uint16_t len)
{
    uint8_t conidx = gap_zero_based_conidx(con_idx);

    TRACE("RX data length %d", len);

    // 分配连接信息
    app_datapath_server_alloc_con_info_with_conidx(conidx);

    // 触发数据接收事件
    if (dp_event_callback) {
        app_dp_rec_data_msg_t data_msg;
        data_msg.data     = (uint8_t *)data;
        data_msg.data_len = len;
        data_msg.conidx   = conidx;
        dp_event_callback(DP_DATA_RECEIVED, (ble_if_app_dp_param_u *)&data_msg);
    }
}

4.5 数据发送流程

4.5.1 通知(Notification)发送
c 复制代码
// ble_datapath_server.c:225-234
void app_datapath_server_send_data_via_notification(uint8_t conidx,
                                                      uint8_t* data,
                                                      uint32_t len)
{
    // 检查通知是否已使能
    if (app_datapath_server_get_tx_ntf_en_by_conidx(conidx)) {
        gatts_send_notification(gap_conn_bf(conidx),
                               g_ble_datapath_tx_character,
                               data,
                               (uint16_t)len);
    }
}
4.5.2 指示(Indication)发送
c 复制代码
// ble_datapath_server.c:236-245
void app_datapath_server_send_data_via_indication(uint8_t conidx,
                                                    uint8_t* data,
                                                    uint32_t len)
{
    if (app_datapath_server_get_tx_ntf_en_by_conidx(conidx)) {
        gatts_send_indication(gap_conn_bf(conidx),
                             g_ble_datapath_tx_character,
                             data,
                             (uint16_t)len);
    }
}

Notification vs Indication:

特性 Notification Indication
应答 无需应答 需要客户端确认
可靠性 不保证到达 保证到达
速度
适用场景 传感器数据、音频流 重要控制命令

4.6 CCCD (Client Characteristic Configuration Descriptor)

CCCD用于客户端使能/禁用通知或指示:

c 复制代码
// ble_datapath_server.c:438-453
case GATT_SERV_EVENT_DESC_WRITE:
{
    gatt_server_desc_write_t *p = param.desc_write;
    uint16_t config = CO_COMBINE_UINT16_LE(p->value);
    bool notify_enabled = false;

    // 检查是否使能通知
    if (config & GATT_CCCD_SET_NOTIFICATION) {
        notify_enabled = true;
    }

    // 更新CCC状态
    app_datapath_server_tx_ccc_changed(svc->con_idx,
                                        svc->connhdl,
                                        notify_enabled);

    // 发送写入响应
    bt_thread_call_func_3(gatts_send_defer_write_rsp,
                          bt_fixed_param(svc->connhdl),
                          bt_fixed_param(p->ctx->token),
                          bt_fixed_param(0));
    return true;
}

CCCD值定义:

  • 0x0000: 禁用通知和指示
  • 0x0001: 使能通知
  • 0x0002: 使能指示
  • 0x0003: 使能通知和指示

5. 断连处理与恢复

5.1 断连原因分类

BLE断连原因定义在HCI规范中:

错误码 宏定义 说明
0x08 CONNECTION_TIMEOUT 连接超时
0x13 REMOTE_USER_TERMINATED 远端用户终止
0x16 LOCAL_HOST_TERMINATED 本地主机终止
0x3D MIC_FAILURE MIC校验失败

5.2 断连事件处理

5.2.1 连接关闭事件
c 复制代码
// app_ble.c:1481-1501
case GAP_CONN_EVENT_CLOSED:
{
    gap_conn_param_t *closed = param.closed;

    CO_LOG_INFO("Connection Closed: idx=%d hdl=%04x reason=%02x",
        closed->con_idx,
        closed->connhdl,
        closed->error_code);

    // 重置连接参数
    app_ble_reset_conn_param_mode(closed->con_idx);

    // 通知应用层
    cb_event.evt_type = BLE_DISCONNECT_EVENT;
    cb_event.p.disconnect_handled.errCode = closed->error_code;
    cb_event.p.disconnect_handled.conidx = gap_zero_based_conidx(closed->con_idx);
    cb_event.p.disconnect_handled.connhdl = closed->connhdl;
    cb_event.p.disconnect_handled.peer_bdaddr.addr_type = closed->peer_type & 0x01;
    memcpy(cb_event.p.disconnect_handled.peer_bdaddr.addr,
           closed->peer_addr.address,
           sizeof(bt_bdaddr_t));

    app_ble_global_handle(&cb_event, NULL);
    break;
}
5.2.2 Datapath断连处理
c 复制代码
// ble_datapath_server.c:300-324
static void app_datapath_server_disconnected(uint8_t con_idx, uint16_t connhdl)
{
    uint8_t conidx = gap_zero_based_conidx(con_idx);

    // 释放连接信息
    if (app_datapath_server_free_con_info_by_conidx(conidx) == BT_STS_SUCCESS) {
        TRACE("Datapath server disconnected");
        tx_done_callback = NULL;
    } else {
        return;
    }

    // 调用断连回调
    if (NULL != disconnected_done_callback) {
        disconnected_done_callback(conidx);
    }

    // 触发断连事件
    if (dp_event_callback) {
        dp_event_callback(DP_DISCONN_DONE, (ble_if_app_dp_param_u *)&conidx);
    }
}
5.2.3 应用层断连处理
c 复制代码
// bes_ble.c:140-210 (平台接口层)
static void datapath_event_cb_box(DP_EVENT_TYPE_E event_type,
                                    ble_if_app_dp_param_u *para_p)
{
    ble_handle_t* ble_handle = &local_ble_callback[BLE_TYPE_CHARGEBOX];

    switch (event_type) {
        case DP_CONN_DONE: {
            TRACE("DP_CONN_DONE: conidx=0x%x handle=%d",
                  para_p->connect_index,
                  gap_zero_based_ble_conidx_as_hdl(para_p->connect_index));

            ble_handle->conidx = para_p->connect_index;
            ble_handle->connected = true;
            ble_handle->callback(BLE_EVENT_CONNECTED, NULL);
            break;
        }

        case DP_DISCONN_DONE:
            TRACE("DP_DISCONN_DONE");
            if (ble_handle != NULL) {
                ble_handle->connected = false;
                ble_handle->callback(BLE_EVENT_DISCONNECTED, NULL);
            }
            ble_handle->conidx = 0xFF;
            break;

        // ... 其他事件处理
    }
}

5.3 主动断连接口

c 复制代码
// bes_ble.c:48-65
void ble_disconnect_box_conn(void)
{
    ble_handle_t* ble_box_handle = &local_ble_callback[BLE_TYPE_CHARGEBOX];
    bt_status_t ble_status = BT_STS_SUCCESS;

    // 检查句柄有效性
    if (ble_box_handle == NULL || ble_box_handle->is_initialized == false) {
        TRACE("ble_box_handle is NULL");
        return;
    }

    // 如果连接有效,则终止连接
    if (ble_box_handle->conidx != 0xFF) {
        ble_status = gap_terminate_connection(ble_box_handle->conidx, 0);
    }

    TRACE("Disconnect: conidx=%d status=%d",
          ble_box_handle->conidx, ble_status);
}

5.4 断连后广播恢复

c 复制代码
// bes_ui_ble_adv.c:299-313
void ui_ble_chargebox_refresh_adv(void)
{
    LOG("Refresh ADV called");

    // 提升CPU频率以快速处理
    ui_freq_boost(BOOST_FREQ_208M, 5000);

    // 检查是否需要停止广播
    if (bt_tws_get_current_role() == BT_TWS_SLAVE_ROLE ||
        ui_is_box_get_ble_connected() ||
        ui_get_para()->ui_state == UI_STATE_IN_CASE_CLOSE ||
        ble_is_box_connected()) {
        // 从耳、已连接、已入盒时停止广播
        ui_ble_chargebox_stop_adv();
    } else {
        // 否则启动快速广播
        ui_ble_chargebox_start_fast_adv_10s();
    }
}

6. 状态机设计

6.1 广播状态机

c 复制代码
typedef struct {
    bool adv_initialized;              // 广播是否已初始化
    box_adv_running_e adv_running;    // 广播运行状态
    bool ble_connected;                // BLE连接状态
    bool need_delay_adv;               // 是否需要延迟广播
    bool is_factory_reset;             // 是否恢复出厂设置
    uint8_t ble_mac[6];                // 缓存的BLE MAC地址
} box_adv_state_t;

状态转换图:

复制代码
         ┌──────────────────────┐
         │  ADV_RUNNING_NONE    │
         │   (未运行/已停止)     │
         └──────┬───────────────┘
                │
                │ start_fast_adv_10s()
                ↓
         ┌──────────────────────┐
         │  ADV_RUNNING_FAST    │
         │    (快速广播30ms)    │
         └──────┬───────────────┘
                │
                │ 10秒定时器到期
                ↓
         ┌──────────────────────┐
         │  ADV_RUNNING_SLOW    │
         │   (慢速广播480ms)    │
         └──────┬───────────────┘
                │
                │ 连接建立 / 入盒 / 恢复出厂
                ↓
         ┌──────────────────────┐
         │  ADV_RUNNING_NONE    │
         │    (停止广播)        │
         └──────────────────────┘

6.2 连接状态机

c 复制代码
typedef struct {
    bes_ble_gatt_callback_t callback;  // 回调函数
    bes_cb_pri_e priority;             // 回调优先级
    bes_ble_type_t type;               // BLE类型
    uint8_t conidx;                      // 连接索引
    bool connected;                      // 连接状态
    bool is_initialized;                 // 初始化状态
} local_cb_info_t;

状态转换:

复制代码
初始化
  ↓
┌────────────────┐
│ DISCONNECTED   │ connected = false, conidx = 0xFF
└────────┬───────┘
         │ GAP_CONN_EVENT_OPENED
         ↓
┌────────────────┐
│  CONNECTED     │ connected = true, conidx = valid
└────────┬───────┘
         │
         │ ← MTU_EXCHANGED
         │ ← CCC_CHANGED
         │ ← DATA_RECEIVED/TX_DONE
         │
         │ GAP_CONN_EVENT_CLOSED
         ↓
┌────────────────┐
│ DISCONNECTED   │ connected = false, conidx = 0xFF
└────────────────┘

6.3 连接参数动态调整

c 复制代码
// app_ble.c:914-1014
void app_ble_update_conn_param_mode_of_specific_connection(uint8_t con_idx,
                                                            BLE_CONN_PARAM_MODE_E mode,
                                                            bool enable)
{
    gap_update_params_t params = {0};
    const BLE_CONN_PARAM_CONFIG_T *pConfig = &ble_conn_param_config[mode];
    uint8_t conidx = gap_zero_based_conidx(con_idx);

    if (conidx > BLE_CONNECTION_MAX) {
        return;
    }

    CO_LOG_INFO("Update conn param: conidx=%d mode=%d enable=%d",
        conidx, mode, enable);

    if (enable) {
        // 添加模式
        if (existingBleConnParamModes[conidx] & (1 << mode)) {
            return;  // 已存在
        }
        existingBleConnParamModes[conidx] |= (1 << mode);

        // 检查是否有更高优先级的模式
        for (index = 0; index < ARRAY_SIZE(ble_conn_param_config); index++) {
            if (((uint32_t)1 << ble_conn_param_config[index].ble_conn_param_mode) &
                existingBleConnParamModes[conidx]) {
                if (ble_conn_param_config[index].priority > pConfig->priority) {
                    return;  // 有更高优先级,不更新
                }
            }
        }
    } else {
        // 移除模式
        if (!(existingBleConnParamModes[conidx] & (1 << mode))) {
            return;  // 不存在
        }
        existingBleConnParamModes[conidx] &= (~(1 << mode));

        if (0 == existingBleConnParamModes[conidx]) {
            // 恢复默认参数
            pConfig = &ble_conn_param_config[0];
            goto label_update;
        }

        // 找到剩余模式中优先级最高的
        pConfig = NULL;
        for (index = 0; index < ARRAY_SIZE(ble_conn_param_config); index++) {
            if ((( uint32_t )1 << ( uint8_t )ble_conn_param_config[index].ble_conn_param_mode) &
                existingBleConnParamModes[conidx]) {
                if (NULL != pConfig) {
                    if (ble_conn_param_config[index].priority > pConfig->priority) {
                        pConfig = &ble_conn_param_config[index];
                    }
                } else {
                    pConfig = &ble_conn_param_config[index];
                }
            }
        }
    }

label_update:
    // 更新连接参数
    params.conn_interval_min_1_25ms = pConfig->conn_interval_min;
    params.conn_interval_max_1_25ms = pConfig->conn_interval_max;
    params.max_peripheral_latency = pConfig->conn_slave_latency_cnt;

    gap_update_le_conn_parameters(gap_zero_based_ble_conidx_as_hdl(conidx),
                                   &params);
}

参数优先级:

复制代码
PRIORITY_HIGH (OTA模式)
    ↑
PRIORITY_ABOVE_NORMAL2 (HFP/服务发现)
    ↑
PRIORITY_ABOVE_NORMAL1 (AI流)
    ↑
PRIORITY_ABOVE_NORMAL0 (A2DP)
    ↑
PRIORITY_NORMAL (默认/空闲)

7. 代码实现分析

7.1 代码架构层次

复制代码
┌─────────────────────────────────────────┐
│        应用层 (App Layer)               │
│  - UI业务逻辑                           │
│  - 充电盒通信                           │
│  - 状态管理                             │
└──────────────┬──────────────────────────┘
               │
┌──────────────┴──────────────────────────┐
│      平台接口层 (Platform Layer)        │
│  bes_ble.c - BLE平台抽象接口          │
│  bes_ble_adv.c - 广播管理             │
└──────────────┬──────────────────────────┘
               │
┌──────────────┴──────────────────────────┐
│      BLE核心层 (BLE Core Layer)         │
│  app_ble.c - BLE核心管理                │
│  ble_datapath_server.c - GATT服务       │
└──────────────┬──────────────────────────┘
               │
┌──────────────┴──────────────────────────┐
│      协议栈层 (Stack Layer)             │
│  GAP Service - 通用访问协议             │
│  GATT Service - 通用属性协议            │
│  L2CAP - 逻辑链路控制                   │
│  HCI - 主机控制接口                     │
└─────────────────────────────────────────┘

7.2 关键数据结构

7.2.1 全局BLE状态
c 复制代码
// app_ble.c:104
static ble_global_t g_ble_global;

typedef struct {
    APP_BLE_CORE_EVENT_CALLBACK ble_core_evt_cb;  // 核心事件回调
    APP_BLE_CORE_GLOBAL_HANDLER_FUNC ble_global_handler[BLE_MAX_CORE_EVT_CB];  // 全局处理器数组
    set_rsp_dist_lk_bit_field_func dist_lk_set_cb;  // 分发密钥回调
    smp_identify_addr_exch_complete ble_smp_info_derived_from_bredr_complete;  // SMP信息派生完成
    uint8_t (*ble_resolving_list_fill_cb)(void);  // 解析列表填充回调
    void (*ble_smp_require_modify)(uint16_t, ble_smp_require_t *);  // SMP需求修改
    void (*ble_get_specific_irk_ia)(uint16_t, uint8_t **, bt_bdaddr_t **);  // 获取特定IRK/IA
    void (*ble_add_record_modify)(uint16_t, BleDevicePairingInfo *);  // 添加记录修改
    bool (*ble_get_specific_record)(uint16_t, const ble_bdaddr_t *, BleDevicePairingInfo *);  // 获取特定记录
    void (*ble_get_specific_hash)(uint16_t, uint8_t **);  // 获取特定哈希
    uint16_t curr_mtu_size[BLE_CONNECTION_MAX];  // 当前MTU大小
    ble_smp_require_t *p_smp_req[BLE_CONNECTION_MAX];  // SMP需求指针
    uint8_t local_database_hash[16];  // 本地数据库哈希
    uint8_t default_tx_pref_phy_bits;  // 默认TX首选PHY位
    uint8_t default_rx_pref_phy_bits;  // 默认RX首选PHY位
    char peer_dev_name[BLE_CONNECTION_MAX][BLE_DEV_NAME_LEN];  // 对端设备名称
    bool adv_force_disabled;  // 广播强制禁用
} ble_global_t;
7.2.2 Datapath连接信息
c 复制代码
// ble_datapath_server.c:123
struct app_datapath_server_env_tag {
    struct {
        uint8_t connectionIndex;       // 连接索引
        bool isNotificationEnabled;    // 通知是否使能
        uint32_t recv_cmd_latest;      // 最新接收的命令
    } con_info[BLE_CONNECTION_MAX];
} app_datapath_server_env;

7.3 MAC地址缓存优化

为避免频繁访问Flash,系统实现了MAC地址缓存:

c 复制代码
// bes_ui_ble_adv.c:320-359
int adv_init(void)
{
    g_box_adv_state.adv_initialized = false;
    g_box_adv_state.ble_connected = false;
    g_box_adv_state.adv_running = BOX_ADV_RUNNING_NONE;

    // 一次性获取并缓存BLE MAC地址
    bt_addr_t local_addr;
    bt_get_local_mac(&local_addr);
    memcpy(g_box_adv_state.ble_mac, local_addr.address, 6);

    LOG("Cached MAC: %02X:%02X:%02X:%02X:%02X:%02X",
        g_box_adv_state.ble_mac[5], g_box_adv_state.ble_mac[4],
        g_box_adv_state.ble_mac[3], g_box_adv_state.ble_mac[2],
        g_box_adv_state.ble_mac[1], g_box_adv_state.ble_mac[0]);

    ble_adv_init();

    // 创建慢速广播定时器
    if (g_chargebox_adv_slow_timer == NULL) {
        g_chargebox_adv_slow_timer = os_create_timer(chargebox_adv_slow_timer_cb,
                                                       os_timer_once);
    }

    // 配置充电盒广播
    ui_ble_adv_chargebox();

    g_box_adv_state.adv_initialized = true;

    // 默认不启动广播,由应用层控制
    ble_adv_enable(BLE_TYPE_CHARGEBOX, false);

    return 0;
}

7.4 线程安全与异步调用

系统大量使用线程调用机制确保回调在正确的线程上下文执行:

c 复制代码
// ble_datapath_server.c:413-415
// 异步发送写入响应
bt_thread_call_func_3(gatts_send_defer_write_rsp,
                      bt_fixed_param(svc->connhdl),
                      bt_fixed_param(p->ctx->token),
                      bt_fixed_param(0));

// app_ble.c:1203-1205
// 异步回复LTK请求
bt_thread_call_func_3(gap_reply_peer_ltk_request,
                      bt_fixed_param(conn->connhdl),
                      bt_fixed_param(positive_reply == false),
                      bt_alloc_param_size(ltk, GAP_KEY_LEN));

8. BLE协议层交互与时序详解

本章详细描述BLE各个关键流程在物理层、链路层和协议层之间的交互,基于Bluetooth Core Specification v5.3最新协议规范。

8.0 BLE协议栈层次交互总览

8.0.1 协议栈层次结构
复制代码
┌──────────────────────────────────────────────────────────────┐
│                    应用层 (Application)                       │
│              (用户应用逻辑、业务处理)                         │
├──────────────────────────────────────────────────────────────┤
│                   GAP & GATT 层                               │
│    GAP: 设备发现、连接管理、安全                             │
│    GATT: 服务发现、数据读写、特征值操作                      │
├──────────────────────────────────────────────────────────────┤
│                 L2CAP (逻辑链路控制)                          │
│    - 数据分段和重组                                           │
│    - 协议复用 (ATT, SMP, Signaling)                           │
│    - 流量控制                                                 │
├──────────────────────────────────────────────────────────────┤
│              HCI (Host Controller Interface)                  │
│    - 命令接口 (Host → Controller)                             │
│    - 事件接口 (Controller → Host)                             │
│    - 数据接口 (双向)                                          │
├══════════════════════════════════════════════════════════════┤
│                链路层 (Link Layer - LL)                       │
│    - 状态机管理 (Standby/Advertising/Scanning/Initiating)    │
│    - 连接管理                                                 │
│    - 数据包格式化                                             │
│    - 加密                                                     │
│    - 流量控制                                                 │
├──────────────────────────────────────────────────────────────┤
│                物理层 (Physical Layer - PHY)                  │
│    - RF射频收发                                               │
│    - 调制/解调 (GFSK)                                         │
│    - 频率跳变                                                 │
│    - 功率控制                                                 │
└──────────────────────────────────────────────────────────────┘

       2.4GHz ISM频段 (2400-2483.5 MHz)
       40个RF通道 (3个广播通道 + 37个数据通道)
8.0.2 各层职责详解
层次 主要职责 关键PDU/消息
应用层 业务逻辑、用户交互 应用数据
GATT 属性协议、服务/特征值 ATT PDU (Read/Write/Notify/Indicate)
GAP 设备角色、连接管理 广播数据、连接参数
L2CAP 数据复用、分段重组 L2CAP PDU
HCI Host-Controller通信 HCI Command/Event/Data
链路层 PDU收发、状态管理 LL PDU (ADV/SCAN/CONN)
物理层 RF信号收发 无线电波

8.1 BLE广播流程详细时序图

8.1.1 广播启动完整时序 (基于Extended Advertising)
复制代码
应用层         GAP          HCI          链路层        物理层
  |             |            |             |             |
  |--开始广播-->|            |             |             |
  |             |            |             |             |
  |             |--设置广播参数----------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Advertising_Parameters |             |
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |  Command    |             |
  |             |            |  Complete   |             |
  |             |            |             |             |
  |             |--设置广播数据----------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Advertising_Data       |             |
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |             |             |
  |             |--设置扫描响应数据------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Scan_Response_Data     |             |
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |             |             |
  |             |--启动广播--------------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Advertising_Enable     |             |
  |             |            |             |             |
  |             |            |             |--进入广播状态-->|
  |             |            |             |             |
  |             |            |             |--配置RF通道-->|
  |             |            |             |  (Ch37,38,39)|
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |  Command    |             |
  |             |            |  Complete   |             |
  |             |            |             |             |
  |             |<-广播启动事件-----------|             |
  |             |  HCI_LE_Extended_       |             |
  |             |  Advertising_Set_       |             |
  |             |  Terminated (if needed) |             |
  |<--广播启动--|            |             |             |
  |   回调      |            |             |             |
  |             |            |             |             |
  |             |            |             |==周期性广播==>|
  |             |            |             |  Adv Interval|
  |             |            |             |  Ch37: ADV_PDU-->发射
  |             |            |             |     ↓ (跳转)   |
  |             |            |             |  Ch38: ADV_PDU-->发射
  |             |            |             |     ↓ (跳转)   |
  |             |            |             |  Ch39: ADV_PDU-->发射
  |             |            |             |     ↓         |
  |             |            |             |  (等待Adv Interval)
  |             |            |             |     ↓         |
  |             |            |             |  (重复)       |
8.1.2 广播数据包在各层的封装
复制代码
应用层数据: "MyDevice" + Service UUID + Manufacturer Data

    ↓ (GAP层封装)

广播数据结构 (AD Structure):
┌────────────────────────────────────────────────┐
│ Length │ Type │ Data                           │
├────────┼──────┼────────────────────────────────┤
│  0x02  │ 0x01 │ 0x06 (Flags)                   │
│  0x09  │ 0x09 │ "MyDevice" (Complete Name)     │
│  0x03  │ 0x03 │ 0x0D 0x18 (16-bit UUID)        │
│  0x08  │ 0xFF │ Company ID + Data              │
└────────┴──────┴────────────────────────────────┘

    ↓ (HCI层传输)

HCI Command: HCI_LE_Set_Extended_Advertising_Data
┌────────────────────────────────────────────────┐
│ Opcode  │ Length │ Handle │ Operation │ Data   │
│ 0x2037  │  N     │  0x01  │   0x03    │  ...   │
└────────────────────────────────────────────────┘

    ↓ (链路层格式化)

LL ADV_PDU:
┌────────────────────────────────────────────────────────┐
│ Preamble │ Access Addr │ PDU Header │ Payload │ CRC   │
│  1 byte  │   4 bytes   │  2 bytes   │ 6-255B  │ 3B    │
└────────────────────────────────────────────────────────┘
PDU Header:
  - PDU Type: ADV_IND (0b0000) / ADV_EXT_IND (0b0111)
  - TxAdd: Address Type
  - RxAdd: Reserved
  - Length: Payload Length

Payload:
  - AdvA (6 bytes): Advertiser Address
  - AdvData: Advertising Data

    ↓ (物理层调制)

RF信号 (GFSK调制):
- 频率: 2402 MHz (Ch37) / 2426 MHz (Ch38) / 2480 MHz (Ch39)
- 符号率: 1 Msym/s
- 调制指数: 0.5
- 发射功率: -20 dBm ~ +10 dBm
8.1.3 Legacy vs Extended Advertising对比
特性 Legacy Advertising Extended Advertising
最大广播数据 31 bytes 255 bytes (可分片至1650 bytes)
广播PHY 1M PHY only 1M, 2M, Coded PHY
广播集数量 1 最多16个同时广播
周期性广播 不支持 支持 Periodic Advertising
功率控制 固定 支持动态调整
HCI命令 HCI_LE_Set_Advertising_* HCI_LE_Set_Extended_Advertising_*

8.2 BLE扫描流程详细时序图

8.2.1 扫描启动完整时序
复制代码
应用层         GAP          HCI          链路层        物理层
  |             |            |             |             |
  |--开始扫描-->|            |             |             |
  |             |            |             |             |
  |             |--设置扫描参数----------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Scan_Parameters        |             |
  |             |  - Scan Type (主动/被动)|             |
  |             |  - Scan Interval        |             |
  |             |  - Scan Window          |             |
  |             |  - Filter Policy        |             |
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |  Command    |             |
  |             |            |  Complete   |             |
  |             |            |             |             |
  |             |--启动扫描--------------->|             |
  |             |  HCI_LE_Set_Extended_   |             |
  |             |  Scan_Enable            |             |
  |             |            |             |             |
  |             |            |             |--进入扫描状态-->|
  |             |            |             |             |
  |             |            |             |--配置RF接收-->|
  |             |            |             |  Ch37,38,39 |
  |             |            |             |             |
  |             |            |<--响应------|             |
  |             |            |             |             |
  |             |            |             |==扫描循环==>|
  |             |            |             |             |
  |             |            |             |  Ch37: 监听<--接收
  |             |            |             |     ↓       |
  |             |            |             |  收到ADV_PDU|
  |             |            |             |     ↓       |
  |             |            |             |<--解析PDU---|
  |             |            |             |  (检查CRC)  |
  |             |            |             |     ↓       |
  |             |            |<--广播报告--|  (过滤)     |
  |             |            |  HCI_LE_    |             |
  |             |            |  Extended_  |             |
  |             |            |  Advertising|             |
  |             |            |  _Report    |             |
  |             |            |             |             |
  |             |<-解析广播数据----------|             |
  |             |  - RSSI   |             |             |
  |             |  - Address|             |             |
  |             |  - AD Data|             |             |
  |             |            |             |             |
  |<--广播回调--|            |             |             |
  |   上报      |            |             |             |
  |             |            |             |             |
  |  (如果是主动扫描)         |             |             |
  |             |            |             |             |
  |             |            |             |--发送SCAN_REQ-->发射
  |             |            |             |  (150μs后)  |
  |             |            |             |             |
  |             |            |             |<--SCAN_RSP--接收
  |             |            |             |  (广告商响应)|
  |             |            |             |     ↓       |
  |             |            |<--扫描响应--|             |
  |             |            |  报告       |             |
  |             |            |             |             |
  |             |<-扫描响应回调----------|             |
  |<--响应数据--|            |             |             |
  |             |            |             |             |
8.2.2 主动扫描vs被动扫描

被动扫描 (Passive Scan):

复制代码
Scanner                    Advertiser
   |                            |
   |  [监听广播通道]             |
   |<--------ADV_IND------------|
   |  (接收广播数据)             |
   |                            |
   |  [解析并上报]               |
   |                            |
   |  [继续监听下一个通道]        |

主动扫描 (Active Scan):

复制代码
Scanner                    Advertiser
   |                            |
   |  [监听广播通道]             |
   |<--------ADV_IND------------|
   |  (接收广播数据)             |
   |                            |
   |--------SCAN_REQ---------->|
   |  (150μs内发送)             |
   |                            |
   |<------SCAN_RSP------------|
   |  (扫描响应数据)             |
   |                            |
   |  [解析并上报]               |
8.2.3 扫描时间参数
复制代码
扫描周期示意图:

|<------- Scan Interval -------->|<------- Scan Interval -------->|
|                                |                                |
|<-- Scan Window -->|   (休眠)   |<-- Scan Window -->|   (休眠)   |
|                   |            |                   |            |
|  [监听并接收ADV]  |  [省电]    |  [监听并接收ADV]  |  [省电]    |
|___________________|____________|___________________|____________|

占空比 = Scan Window / Scan Interval

示例配置:
- Scan Interval = 100ms  (160 * 0.625ms)
- Scan Window   = 50ms   (80 * 0.625ms)
- 占空比 = 50%
- 功耗适中,发现速度快

8.3 BLE连接建立流程详细时序图

8.3.1 连接建立完整时序 (Initiator发起)
复制代码
Central(主机)    GAP         HCI         链路层       物理层    |    物理层      链路层      HCI        GAP     Peripheral(从机)
    |            |            |            |            |       |      |           |           |          |           |
    |--发起连接->|            |            |            |       |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |--设置连接参数---------->|            |       |      |           |           |          |           |
    |            |  HCI_LE_Extended_       |            |       |      |           |           |          |           |
    |            |  Create_Connection      |            |       |      |           |           |          |           |
    |            |  - Peer Address         |            |       |      |           |           |          |           |
    |            |  - Conn Interval        |            |       |      |           |           |          |           |
    |            |  - Conn Latency         |            |       |      |           |           |          |           |
    |            |  - Supervision Timeout  |            |       |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |<-响应------|            |       |      |           |           |          |           |
    |            |            |  Command   |            |       |      |           |           |          |           |
    |            |            |  Status    |            |       |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |<==广播中==|
    |            |            |            |            |       |      |           |           |          |  ADV_IND  |
    |            |            |            |--进入发起状态-->    |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |==扫描目标设备==>   |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |<--------ADV_IND-----------|<========ADV_IND======|          |           |
    |            |            |            |  (收到目标广播)    |       |      发射|           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |-------CONNECT_IND-------->|发射      |           |          |           |
    |            |            |            |  (150μs内)        |       |          |           |          |           |
    |            |            |            |            |       |      |    接收<-CONNECT_IND-|          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |--建立连接-->|       |      |<--建立连接-----------|          |           |
    |            |            |            |  状态      |       |      |  状态     |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |  CONNECT_IND PDU内容:                             |       |      |           |           |          |           |
    |  - InitA (发起者地址)                              |       |      |           |           |          |           |
    |  - AdvA (广播者地址)                               |       |      |           |           |          |           |
    |  - Access Address (连接使用)                       |       |      |           |           |          |           |
    |  - CRC Init                                       |       |      |           |           |          |           |
    |  - WinSize, WinOffset                             |       |      |           |           |          |           |
    |  - Interval, Latency, Timeout                     |       |      |           |           |          |           |
    |  - Channel Map (37个数据通道)                      |       |      |           |           |          |           |
    |  - Hop Increment (跳频增量)                        |       |      |           |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |==连接建立==>|       |      |<==连接建立==         |          |           |
    |            |            |            |  transmitWindowOffset     |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |<--首个数据包->发射  |       |接收<--首个数据包-----|          |           |
    |            |            |            |  LL_DATA   |       |      |  LL_DATA  |           |          |           |
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |<-连接完成事件----------|       |      |-连接完成事件--------->|          |           |
    |            |            |  HCI_LE_Connection_    |       |      |  HCI_LE_  |           |          |           |
    |            |            |  Complete              |       |      |  Connection          |          |           |
    |            |            |  - Handle              |       |      |  _Complete|           |          |           |
    |            |            |  - Role (Master)       |       |      |  - Handle |           |          |           |
    |            |            |  - Peer Address        |       |      |  - Role (Slave)      |          |           |
    |            |            |  - Conn Interval       |       |      |  - Peer   |           |          |           |
    |            |            |            |            |       |      |  Address  |           |          |           |
    |            |<-连接建立回调---------|            |       |      |           |-连接建立回调------>|           |
    |<-连接成功--|            |            |            |       |      |           |           |          |--连接成功->|
    |            |            |            |            |       |      |           |           |          |           |
    |            |            |            |==数据通道通信==>    |       |<==数据通道通信==     |          |           |
    |            |            |            |  (频率跳变)  |       |      |  (频率跳变)          |          |           |
8.3.2 CONNECT_IND PDU详细结构
复制代码
CONNECT_IND / CONNECT_REQ PDU:

┌─────────────────────────────────────────────────────────────┐
│ PDU Header (2 bytes)                                        │
├─────────────────────────────────────────────────────────────┤
│ PDU Type: 0b0101 (CONNECT_IND) / 0b1101 (AUX_CONNECT_REQ)  │
│ TxAdd: Initiator地址类型                                    │
│ RxAdd: Advertiser地址类型                                   │
│ Length: 34 bytes                                            │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ Payload (34 bytes)                                          │
├─────────────────────────────────────────────────────────────┤
│ InitA (6 bytes):    发起者蓝牙地址                          │
│ AdvA (6 bytes):     广播者蓝牙地址                          │
│ LLData (22 bytes):  链路层数据                              │
│   ├─ Access Address (4 bytes):  连接使用的访问地址          │
│   ├─ CRC Init (3 bytes):        CRC初始值                   │
│   ├─ WinSize (1 byte):          发送窗口大小 (1.25ms单位)   │
│   ├─ WinOffset (2 bytes):       发送窗口偏移 (1.25ms单位)   │
│   ├─ Interval (2 bytes):        连接间隔 (1.25ms单位)       │
│   ├─ Latency (2 bytes):         从设备延迟                  │
│   ├─ Timeout (2 bytes):         监督超时 (10ms单位)         │
│   ├─ ChM (5 bytes):             通道映射 (37个数据通道)     │
│   └─ Hop & SCA (1 byte):                                    │
│       - Hop Increment (5 bits): 跳频增量 (5-16)             │
│       - SCA (3 bits):           睡眠时钟精度                │
└─────────────────────────────────────────────────────────────┘

连接参数示例:
- Access Address: 0x8E89BED6 (随机生成,符合规则)
- Interval: 24 (30ms)
- Latency: 0 (无延迟)
- Timeout: 500 (5000ms)
- Channel Map: 0x1FFFFFFFFF (全部37个通道启用)
- Hop: 7 (跳频增量)
8.3.3 连接建立时间线
复制代码
时间轴 (Advertiser视角):

T0: 发送ADV_IND
    |
    ├─ T0 + 150μs (最大): 接收窗口关闭
    |   (Initiator必须在此之前发送CONNECT_IND)
    |
    ├─ T0 + 150μs ~ T0 + 10ms: 可能收到CONNECT_IND
    |   (实际取决于Initiator处理时间)
    |
T1: 收到CONNECT_IND
    |
    ├─ 立即停止广播
    |
    ├─ 解析连接参数
    |   - Access Address
    |   - Channel Map
    |   - Hop Increment
    |   - Timing Parameters
    |
T2: T1 + transmitWindowOffset
    |
    ├─ 打开接收窗口 (transmitWindowSize)
    |
    ├─ 等待首个数据包
    |
T3: T2 + (0 ~ transmitWindowSize)
    |
    ├─ 收到首个LL_DATA_PDU
    |
    ├─ 连接同步完成
    |
    └─ 开始正常连接事件

连接建立总时间: T3 - T0
典型值: 6ms ~ 10ms (取决于transmitWindowOffset配置)

8.4 BLE配对鉴权流程详细时序图

8.4.1 LE Legacy Pairing (传统配对)
复制代码
Central(主机)    GAP/SMP     HCI         链路层   |   链路层      HCI       GAP/SMP   Peripheral(从机)
    |              |          |            |       |      |         |           |            |
    |              |          |    [已建立LE连接]  |       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |--发起配对--->|          |            |       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |              |--Pairing Request---->|--L2CAP(SMP)-->|-------->|----Pairing Request---->|
    |              |  (SMP命令)  |         |       |      |         |  (SMP命令)  |            |
    |              |  - IO Capability     |       |      |         |  - IO Capability        |
    |              |  - OOB Flag          |       |      |         |  - OOB Flag |            |
    |              |  - Auth Req          |       |      |         |  - Auth Req |            |
    |              |  - Max Key Size      |       |      |         |  - Max Key Size         |
    |              |  - Init Key Dist     |       |      |         |  - Init Key Dist        |
    |              |  - Resp Key Dist     |       |      |         |  - Resp Key Dist        |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |         |           |<--检查能力-|
    |              |          |            |       |      |         |           |   决定配对方法
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |<--------|<----Pairing Response---|
    |              |<---Pairing Response--|<--L2CAP(SMP)--|         |  (SMP命令)  |            |
    |              |          |            |       |      |         |           |            |
    |--选择配对方法|          |            |       |      |         |  配对方法--|            |
    |  (Just Works/Passkey/OOB)         |       |      |         |   选择      |            |
    |              |          |            |       |      |         |           |            |
    | === Phase 1: Pairing Feature Exchange (完成) ===  |      === Phase 1: 完成 ===       |
    |              |          |            |       |      |         |           |            |
    | === Phase 2: Short Term Key (STK) Generation === |      === Phase 2: STK生成 ===    |
    |              |          |            |       |      |         |           |            |
    |  (如果是Passkey Entry)           |       |      |         |           |            |
    |<--显示/输入配对码--|            |       |      |         |  --显示/输入配对码-->      |
    |  "123456"    |          |            |       |      |         |  "123456"   |            |
    |              |          |            |       |      |         |           |            |
    |              |---Pairing Confirm--->|------->|----->|-------->|---Pairing Confirm----->|
    |              |  Mconfirm = c1(TK, Sconfirm,  |      |         |  Sconfirm  |            |
    |              |               Preq, Pres...)  |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |<--------|<----Pairing Random-----|
    |              |<---Pairing Random----|<-------|------|         |  Srand     |            |
    |              |  Srand   |            |       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |--验证Sconfirm|          |            |       |      |         |--验证Mconfirm--------->|
    |              |          |            |       |      |         |           |            |
    |              |---Pairing Random---->|------->|----->|-------->|---Pairing Random----->|
    |              |  Mrand   |            |       |      |         |  Mrand     |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |         |           |--验证Mconfirm
    |              |          |            |       |      |         |           |            |
    |--生成STK-----|          |            |       |      |         |--生成STK---|            |
    |  STK = s1(TK, Srand, Mrand)        |       |      |         |  STK = s1(TK, Srand, Mrand)
    |              |          |            |       |      |         |           |            |
    | === Phase 3: Link Encryption ===              |      === Phase 3: 链路加密 ===       |
    |              |          |            |       |      |         |           |            |
    |              |--HCI_LE_Start_Encryption----->|      |         |           |            |
    |              |  (使用STK)           |       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |--LL_ENC_REQ-->发射     |         |           |            |
    |              |          |            |       |      |    接收<-LL_ENC_REQ------------|            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |    发射--LL_ENC_RSP---------->|            |
    |              |          |            |<--LL_ENC_RSP--|接收     |           |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |==开始加密通信==|      |==开始加密通信==        |            |
    |              |          |            |       |      |         |           |            |
    |              |          |<--Encryption Changed-------|      |--Encryption Changed---->|            |
    |              |          |  Event    |       |      |         |  Event     |            |
    |              |          |            |       |      |         |           |            |
    | === Phase 4: Key Distribution ===             |      === Phase 4: 密钥分发 ===       |
    |              |          |            |       |      |         |           |            |
    |              |---Encryption Information---->|----->|-------->|---Encryption Info----->|
    |              |  LTK, EDIV, Rand    |       |      |         |  (长期密钥)  |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |<--------|<----Encryption Info----|
    |              |<---Encryption Information----|<-----|---------|  LTK, EDIV, Rand        |
    |              |          |            |       |      |         |           |            |
    |              |---Identity Information------>|----->|-------->|---Identity Info------->|
    |              |  IRK, Address       |       |      |         |  (身份密钥)  |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |<--------|<----Identity Info------|
    |              |<---Identity Information------|<-----|---------|  IRK, Address           |
    |              |          |            |       |      |         |           |            |
    |              |---Signing Information------->|----->|-------->|---Signing Info-------->|
    |              |  CSRK (连接签名密钥)|       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |<--------|<----Signing Info------|
    |              |<---Signing Information-------|<-----|---------|  CSRK      |            |
    |              |          |            |       |      |         |           |            |
    |--保存密钥到NV|          |            |       |      |         |--保存密钥到NV-------->|
    |              |          |            |       |      |         |           |            |
    |              |          |            |       |      |         |           |            |
    |<--配对完成---|          |            |       |      |         |--配对完成--|            |
    |              |          |            |       |      |         |           |            |
8.4.2 LE Secure Connections (安全连接配对 - BLE 4.2+)
复制代码
Central         GAP/SMP     链路层    |   链路层      GAP/SMP    Peripheral
  |               |           |        |      |          |            |
  |               |    [已建立LE连接]  |       |      |          |            |
  |               |           |        |      |          |            |
  |--发起配对--->|           |        |      |          |            |
  |               |           |        |      |          |            |
  |               |--Pairing Request-->|----->|--------->|--Pairing Request-->|
  |               |  SecureConn=1     |        |      |          |  检查能力   |
  |               |           |        |      |          |            |
  |               |           |        |      |<---------|<--Pairing Response-|
  |               |<--Pairing Response|<------|----------|  SecureConn=1      |
  |               |           |        |      |          |            |
  | === Phase 1: Feature Exchange (完成) ===  |      === Phase 1完成 ===     |
  |               |           |        |      |          |            |
  | === Phase 2: Public Key Exchange ===     |      === Phase 2: 公钥交换 === |
  |               |           |        |      |          |            |
  |--生成ECDH密钥对----------|        |      |          |--生成ECDH密钥对--->|
  |  (P-256椭圆曲线)          |        |      |          |  (P-256)   |            |
  |  PKa (公钥64字节)         |        |      |          |  PKb (公钥64字节)        |
  |  SKa (私钥32字节)         |        |      |          |  SKb (私钥32字节)        |
  |               |           |        |      |          |            |
  |               |--Pairing Public Key------>|-------->|--Public Key-------->|
  |               |  PKa (64 bytes)   |        |      |          |  PKa       |            |
  |               |           |        |      |          |            |
  |               |           |        |      |<---------|<--Pairing Public Key|
  |               |<--Pairing Public Key------|----------|  PKb (64 bytes)     |
  |               |  PKb      |        |      |          |            |
  |               |           |        |      |          |            |
  |--验证公钥-----|           |        |      |          |--验证公钥--|            |
  |  (检查点是否在曲线上)     |        |      |          |            |
  |               |           |        |      |          |            |
  |--计算DHKey----|           |        |      |          |--计算DHKey-|            |
  |  DHKey = P-256(SKa, PKb)  |        |      |          |  DHKey = P-256(SKb, PKa)|
  |  (共享密钥)   |           |        |      |          |  (相同)    |            |
  |               |           |        |      |          |            |
  | === Phase 2.1: Authentication Stage 1 (Passkey Entry示例) ===            |
  |               |           |        |      |          |            |
  |<--输入Passkey-|           |        |      |          |--显示Passkey---------->|
  |  "123456"     |           |        |      |          |  "123456"  |            |
  |               |           |        |      |          |            |
  |  (将Passkey转为ra[0..19]比特)    |      |          |  (转换)    |            |
  |               |           |        |      |          |            |
  |  For i = 0 to 19:                 |      |          |  For i = 0 to 19:      |
  |    生成Nai, 计算Cai = f4(PKax, PKbx, Nai, ra[i])  |    计算Cbi = f4(PKbx, PKax, Nbi, ra[i])
  |               |           |        |      |          |    生成Nbi |            |
  |               |           |        |      |          |            |
  |               |--Pairing Confirm-->|----->|--------->|--Confirm--->|            |
  |               |  Cai      |        |      |          |  (20轮)    |            |
  |               |           |        |      |          |            |
  |               |           |        |      |<---------|<--Pairing Confirm------|
  |               |<--Pairing Confirm-|<------|----------|  Cbi       |            |
  |               |           |        |      |          |            |
  |               |--Pairing Random--->|----->|--------->|--Random---->|            |
  |               |  Nai      |        |      |          |  验证Cbi   |            |
  |               |           |        |      |          |            |
  |               |           |        |      |<---------|<--Pairing Random-------|
  |               |<--Pairing Random--|<------|----------|  Nbi       |            |
  |--验证Cai-----|           |        |      |          |            |
  |               |           |        |      |          |            |
  | === Phase 2.2: Authentication Stage 2 ===  |      === Stage 2 ===             |
  |               |           |        |      |          |            |
  |--计算MacKey和LTK---------|        |      |          |--计算MacKey和LTK------>|
  |  MacKey = f5(DHKey, Na, Nb, ...)  |      |          |  (相同)    |            |
  |  LTK = f5(DHKey, Na, Nb, ...)     |      |          |            |
  |               |           |        |      |          |            |
  |--计算Ea-------|           |        |      |          |--计算Eb----|            |
  |  Ea = f6(MacKey, Na, Nb, ...)     |      |          |  Eb = f6(MacKey, Nb, Na, ...)|
  |               |           |        |      |          |            |
  |               |--DHKey Check------>|----->|--------->|--DHKey Check---------->|
  |               |  Ea       |        |      |          |  验证Ea    |            |
  |               |           |        |      |          |            |
  |               |           |        |      |<---------|<--DHKey Check----------|
  |               |<--DHKey Check-----|<------|----------|  Eb        |            |
  |--验证Eb-------|           |        |      |          |            |
  |               |           |        |      |          |            |
  | === Phase 3: Link Encryption (使用LTK) === |      === Phase 3 ===            |
  |               |           |        |      |          |            |
  |               |--Start Encryption->|      |          |            |
  |               |  (LTK)    |        |      |          |            |
  |               |           |--LL_ENC_REQ-->|--------->|----------->|            |
  |               |           |        |      |<---------|<--LL_ENC_RSP-----------|
  |               |           |<--LL_ENC_RSP--|          |            |
  |               |           |        |      |          |            |
  |               |           |==加密连接==   |      |==加密连接==   |            |
  |               |           |        |      |          |            |
  | === Phase 4: Key Distribution ===          |      === Phase 4 ===            |
  |               |           |        |      |          |            |
  |               |  (IRK, CSRK交换,同Legacy Pairing)                            |
  |               |           |        |      |          |            |
  |<--配对完成----|           |        |      |          |--配对完成->|            |
8.4.3 配对方法选择决策表

根据双方的IO能力(IO Capability)和认证需求,选择配对方法:

Initiator IO Responder IO 配对方法 说明
DisplayOnly DisplayOnly Just Works 无MITM保护
DisplayOnly DisplayYesNo Just Works 无MITM保护
DisplayOnly KeyboardOnly Passkey Entry Responder输入
DisplayOnly NoInputNoOutput Just Works 无MITM保护
DisplayOnly KeyboardDisplay Passkey Entry Responder输入
DisplayYesNo DisplayOnly Just Works 无MITM保护
DisplayYesNo DisplayYesNo Numeric Comparison 双方确认
DisplayYesNo KeyboardOnly Passkey Entry Responder输入
DisplayYesNo NoInputNoOutput Just Works 无MITM保护
DisplayYesNo KeyboardDisplay Numeric Comparison 双方确认
KeyboardOnly DisplayOnly Passkey Entry Initiator输入
KeyboardOnly DisplayYesNo Passkey Entry Initiator输入
KeyboardOnly KeyboardOnly Passkey Entry 双方输入
KeyboardOnly NoInputNoOutput Just Works 无MITM保护
KeyboardOnly KeyboardDisplay Passkey Entry Initiator输入
NoInputNoOutput * Just Works 无MITM保护
KeyboardDisplay DisplayOnly Passkey Entry Initiator输入
KeyboardDisplay DisplayYesNo Numeric Comparison 双方确认
KeyboardDisplay KeyboardOnly Passkey Entry Responder输入
KeyboardDisplay NoInputNoOutput Just Works 无MITM保护
KeyboardDisplay KeyboardDisplay Numeric Comparison 双方确认

8.5 BLE拒绝连接流程详细时序图

8.5.1 广播端拒绝连接 (使用白名单过滤)
复制代码
Initiator      链路层       物理层   |   物理层      链路层      GAP      Peripheral
   |             |            |       |      |          |          |           |
   |             |            |       |      |<==广播中=|          |           |
   |             |            |       |      |  ADV_IND |          |           |
   |             |            |       |      |  (设置了白名单过滤)  |           |
   |             |            |       |      |  Filter Policy = 0x03            |
   |             |            |       |      |  (仅白名单连接)     |           |
   |             |            |       |      |          |          |           |
   |--发起连接---|            |       |      |          |          |           |
   |             |            |       |      |          |          |           |
   |             |--扫描目标->|       |      |          |          |           |
   |             |            |       |      |          |          |           |
   |             |<-----ADV_IND---------|接收<|发射      |          |           |
   |             |            |       |      |          |          |           |
   |             |--CONNECT_IND------->|发射  |          |          |           |
   |             |  InitA=AA:BB:CC:... |       |   接收<-CONNECT_IND-----------||
   |             |  (不在白名单中)     |       |      |          |  检查白名单-|
   |             |            |       |      |          |  InitA不在白名单      |
   |             |            |       |      |          |          ↓           |
   |             |            |       |      |          |  **忽略CONNECT_IND** |
   |             |            |       |      |          |          |           |
   |             |            |       |      |<==继续广播==       |           |
   |             |            |       |      |  ADV_IND |          |           |
   |             |            |       |      |          |          |           |
   |--等待连接响应------------|       |      |          |          |           |
   |  (transmitWindow)        |       |      |          |          |           |
   |             |            |       |      |          |          |           |
   |--超时-------|            |       |      |          |          |           |
   |  (没有收到首个数据包)    |       |      |          |          |           |
   |             |            |       |      |          |          |           |
   |<--连接失败事件----------|       |      |          |          |           |
   |  HCI_LE_Connection_Complete     |      |          |          |           |
   |  Status: 0x3E (Connection Failed|      |          |          |           |
   |             to be Established)  |       |      |          |          |           |
   |             |            |       |      |          |          |           |

原因分析:
1. Peripheral设置了白名单过滤策略
2. Initiator地址不在白名单中
3. Peripheral链路层直接丢弃CONNECT_IND
4. 不会通知上层应用
5. Initiator等待transmitWindow超时后报告连接失败
8.5.2 应用层主动拒绝连接请求
复制代码
Initiator      链路层    |   链路层      HCI        GAP       应用层    Peripheral
   |             |        |      |         |          |           |            |
   |--发起连接---|        |      |         |          |           |            |
   |             |        |      |         |          |           |            |
   |             |<====CONNECT_IND接收====|          |           |            |
   |             |        |      |         |          |           |            |
   |             |        |      |--连接请求事件----->|           |            |
   |             |        |      |  HCI_LE_Connection_Complete    |            |
   |             |        |      |  Status: 0x00 (成功)           |            |
   |             |        |      |  Handle: 0x0040  |           |            |
   |             |        |      |         |          |           |            |
   |             |        |      |         |--连接回调---------->|            |
   |             |        |      |         |  peer_addr          |            |
   |             |        |      |         |  role: Slave        |            |
   |             |        |      |         |          |           |            |
   |             |        |      |         |          |           |--检查连接条件
   |             |        |      |         |          |           |  (黑名单/白名单)
   |             |        |      |         |          |           |  (连接数限制)
   |             |        |      |         |          |           |  (电池电量)
   |             |        |      |         |          |           |  (其他业务逻辑)
   |             |        |      |         |          |           |            |
   |             |        |      |         |          |           |<--决策:拒绝|
   |             |        |      |         |          |           |            |
   |             |        |      |         |          |<--断开连接-------------|
   |             |        |      |         |          |  Reason: 拒绝连接       |
   |             |        |      |         |          |           |            |
   |             |        |      |         |<-HCI_Disconnect-----|            |
   |             |        |      |         |  Handle: 0x0040     |            |
   |             |        |      |         |  Reason: 0x13       |            |
   |             |        |      |         |  (Remote User       |            |
   |             |        |      |         |   Terminated)       |            |
   |             |        |      |         |          |           |            |
   |             |        |      |<--LL_TERMINATE_IND-----------|            |
   |             |        |      |  ErrorCode: 0x13|           |            |
   |             |<====LL_TERMINATE_IND接收==|      |           |            |
   |             |        |      |         |          |           |            |
   |<--断开连接事件------|       |      |         |          |           |            |
   |  HCI_Disconnection_ |       |      |         |          |           |            |
   |  Complete           |       |      |         |          |           |            |
   |  Reason: 0x13       |       |      |         |          |           |            |
   |             |        |      |         |          |           |            |

拒绝原因码 (BLE常用):
- 0x05: Authentication Failure
- 0x0D: Connection Rejected due to Limited Resources
- 0x0E: Connection Rejected Due to Security Reasons
- 0x0F: Connection Rejected due to Unacceptable BD_ADDR
- 0x13: Remote User Terminated Connection
- 0x16: Connection Terminated by Local Host
8.5.3 链路层拒绝连接 (无资源)
复制代码
Initiator      链路层    |   链路层      HCI        GAP      Peripheral
   |             |        |      |         |          |           |
   |             |        |      |  [已有最大连接数]  |           |
   |             |        |      |         |          |           |
   |--发起连接---|        |      |         |          |           |
   |             |        |      |         |          |           |
   |             |<====CONNECT_IND接收====|          |           |
   |             |        |      |         |          |           |
   |             |        |      |--检查连接资源------|           |
   |             |        |      |  可用连接槽: 0     |           |
   |             |        |      |  (BLE_CONNECTION_MAX已满)      |
   |             |        |      |         ↓          |           |
   |             |        |      |  **无法接受新连接**|           |
   |             |        |      |         |          |           |
   |             |        |      |--立即发送LL_TERMINATE_IND----->|
   |             |        |      |  ErrorCode: 0x0D   |           |
   |             |        |      |  (Connection Rejected          |
   |             |        |      |   Limited Resources)           |
   |             |        |      |         |          |           |
   |             |<====LL_TERMINATE_IND接收==        |           |
   |             |        |      |         |          |           |
   |<--连接完成事件------|       |      |         |          |           |
   |  HCI_LE_Connection_ |       |      |         |          |           |
   |  Complete           |       |      |         |          |           |
   |  Status: 0x0D       |       |      |         |          |           |
   |  (Limited Resources)|       |      |         |          |           |
   |             |        |      |         |          |           |

8.6 BLE断开连接流程详细时序图

8.6.1 主动断开连接 (Host发起)
复制代码
应用层        GAP         HCI        链路层      物理层   |   物理层     链路层      HCI       GAP      应用层
  |            |           |           |           |       |      |          |          |         |          |
  |--断开连接->|           |           |           |       |      |          |          |         |          |
  |  (用户操作/超时/其他)  |           |           |       |      |          |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |--HCI_Disconnect------>|           |       |      |          |          |         |          |
  |            |  Handle: 0x0040       |           |       |      |          |          |         |          |
  |            |  Reason: 0x13         |           |       |      |          |          |         |          |
  |            |  (Remote User         |           |       |      |          |          |         |          |
  |            |   Terminated)         |           |       |      |          |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |<--Command Status-----|       |      |          |          |         |          |
  |            |           |  Status: 0x00        |       |      |          |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |           |--LL_TERMINATE_IND->发射  |          |          |         |          |
  |            |           |           |  ErrorCode: 0x13  |       |   接收<-LL_TERMINATE_IND----|          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |           |==停止数据传输==>  |       |<==停止数据传输==          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |           |--等待6个连接事件->|       |      |<-等待确认--|          |         |          |
  |            |           |           |  (确保对方收到)  |       |      |          |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |           |<--关闭连接--------|       |      |--关闭连接->|          |         |          |
  |            |           |           |  释放资源         |       |      |  释放资源  |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |           |<--Disconnection Complete-----|      |--Disconnection Complete--->|          |
  |            |           |  Handle: 0x0040      |       |      |  Handle   |          |         |          |
  |            |           |  Reason: 0x13        |       |      |  Reason   |          |         |          |
  |            |           |           |           |       |      |          |          |         |          |
  |            |<--断开回调-----------|           |       |      |          |--断开回调-------->|          |
  |<--断开通知-|           |           |           |       |      |          |          |         |--断开通知>|
  |            |           |           |           |       |      |          |          |         |          |
8.6.2 监督超时断开 (Supervision Timeout)
复制代码
Central       链路层      HCI        |        HCI       链路层     Peripheral
  |             |          |          |          |          |           |
  |      [正常连接通信]    |          |          |    [正常连接通信]    |
  |             |          |          |          |          |           |
  |==连接事件==>|          |          |          |<==连接事件==         |
  |             |<------数据包--------|接收      |发射--数据包--------->|
  |             |          |          |          |          |           |
  |             |-------数据包------->|发射      |接收<--数据包---------|
  |             |          |          |          |          |           |
  |    ... (多个连接事件) ...        |          |          |           |
  |             |          |          |          |          |           |
  |             |          |          |          |     [出现干扰/距离过远]
  |             |          |          |          |          |           |
  |==连接事件==>|          |          |          |<==连接事件==         |
  |             |-------数据包------->|发射      |          |           |
  |             |          |          |          |    **未收到** (丢包) |
  |             |          |          |          |          |           |
  |             |<------未收到ACK-----|          |          |           |
  |             |          |          |          |          |           |
  |==连接事件==>|          |          |          |<==连接事件==         |
  |             |-------数据包------->|发射      |          |           |
  |             |  (重传)  |          |          |    **未收到** (丢包) |
  |             |          |          |          |          |           |
  |    ... (持续丢包) ...            |          |          |           |
  |             |          |          |          |          |           |
  |             |--监督定时器计数-----|          |          |--监督定时器计数----|
  |             |  timeout_counter++  |          |          |  timeout_counter++ |
  |             |          |          |          |          |           |
  |    ... (继续尝试通信) ...        |          |          |           |
  |             |          |          |          |          |           |
  |             |--超时检查-----------|          |          |--超时检查--|           |
  |             |  if (time_elapsed   |          |          |  if (time_elapsed)  |
  |             |      >= Supervision |          |          |      >= Supervision |
  |             |         Timeout)    |          |          |         Timeout)    |
  |             |          |          |          |          |           |
  |             |     **超时触发**    |          |          |     **超时触发**    |
  |             |          |          |          |          |           |
  |             |<--关闭连接----------|          |          |--关闭连接->|           |
  |             |  释放资源           |          |          |  释放资源  |           |
  |             |          |          |          |          |           |
  |             |<--Disconnection Complete-------|--Disconnection Complete----->|
  |             |  Status: 0x00       |          |          |  Status   |           |
  |             |  Reason: 0x08       |          |          |  Reason: 0x08         |
  |             |  (Connection Timeout)          |          |  (Connection Timeout) |
  |             |          |          |          |          |           |

监督超时参数:
- 范围: 100ms ~ 32s (0x000A ~ 0x0C80 * 10ms)
- 典型值: 5s (500 * 10ms)
- 必须满足: Timeout > (1 + Latency) * Interval * 2
- 超时后双方独立关闭连接,不交换LL_TERMINATE_IND
8.6.3 链路层即时断开 (LL_TERMINATE_IND)
复制代码
Device A      链路层    |   链路层     Device B
   |             |       |      |          |
   |      [连接中]       |      |    [连接中]
   |             |       |      |          |
   |--检测到错误-|       |      |          |
   |  (MIC失败/ |       |      |          |
   |   版本不兼容)       |      |          |
   |             |       |      |          |
   |             |--发送LL_TERMINATE_IND-->|发射
   |             |  ErrorCode: 0x3D        |
   |             |  (MIC Failure)  |       |   接收<-LL_TERMINATE_IND
   |             |       |      |          |
   |             |--立即关闭连接->|        |<--立即关闭连接---
   |             |  (无需等待确认)|        |  (收到即关闭)
   |             |       |      |          |
   |             |<--Disconnection Complete|--Disconnection Complete-->
   |             |       |      |          |
   |<--上报断开--|       |      |          |--上报断开->
   |             |       |      |          |

LL_TERMINATE_IND PDU格式:
┌────────────────────────────┐
│ LLID: 0b11 (LL Control PDU)│
│ NESN, SN, MD              │
│ Length: 2                  │
├────────────────────────────┤
│ Opcode: 0x02              │
│ ErrorCode: 1 byte          │
└────────────────────────────┘

常见ErrorCode:
- 0x05: Authentication Failure
- 0x13: Remote User Terminated Connection
- 0x16: Connection Terminated by Local Host
- 0x3B: Unacceptable Connection Parameters
- 0x3D: Connection Terminated Due to MIC Failure
- 0x3E: Connection Failed to be Established

8.7 HCI日志分析实例

8.7.1 广播启动日志解析

从日志分析广播启动的完整流程:

复制代码
时间戳: 15:49:47:495

1. 广播数据刷新触发
   [I] BLE : 00ad #3335 FADV 2c244a9b
   → 准备刷新广播数据

2. 禁用旧广播
   [I] BLE : 00a5 #3310 FDIS 01
   → 禁用广播句柄0x01

3. 设置广播参数
   [TX]: 01 36 20 19 02 13 00 40 00 00 60 00 00 07 02 00 44 b1 49 13 e9 7c 00 fb 01 00 01 01 00
   解析:
   - 01: HCI Command
   - 36 20: Set Extended Advertising Parameters (0x2036)
   - 02: Advertising Handle
   - 间隔参数: 0x0040 = 64 * 0.625ms = 40ms

   [RX]: 04 0e 05 05 36 20 00 fb
   → 控制器响应: 状态0x00(成功), Selected TX Power

4. 设置广播数据
   [TX]: 01 37 20 0e 02 03 00 0a 06 16 2c fe 99 f5 0e 02 0a f5
   解析:
   - 37 20: Set Extended Advertising Data (0x2037)
   - 02: Handle
   - 03 00: Operation (Complete)
   - 0a: Length
   - 广播数据: 06 16 2c fe 99 f5 0e 02 0a f5

   [RX]: 04 0e 04 05 37 20 00
   → 控制器响应: 成功

5. 设置扫描响应数据(如果需要)
   [TX]: 01 38 20 24 02 03 00 20 1f 09 73 6f 75 6e 64 63 6f 72 65 ...
   解析:
   - 38 20: Set Extended Scan Response Data (0x2038)
   - 包含完整本地名称

6. 启动广播
   [TX]: 01 39 20 06 01 01 02 00 00 00
   解析:
   - 39 20: LE Set Extended Advertising Enable (0x2039)
   - 01: Enable
   - 01: Number of sets
   - 02: Advertising Handle
   - 00 00 00: Duration, Max Events

   [RX]: 04 0e 04 05 39 20 0c
   → 控制器响应: 错误码0x0c (Command Disallowed)

   重试:
   [TX]: 01 39 20 06 01 01 08 00 00 00
   使用不同的Handle(0x08)

   [RX]: 04 0e 04 05 39 20 0b
   → 错误码0x0b (Command Disallowed - 可能是快速重复命令)

时序图:

复制代码
主机                                控制器
  │                                    │
  ├──── Set Adv Params (0x2036) ─────>│
  │<───── Command Complete ───────────┤
  │                                    │
  ├──── Set Adv Data (0x2037) ───────>│
  │<───── Command Complete ───────────┤
  │                                    │
  ├──── Set Scan Rsp (0x2038) ───────>│
  │<───── Command Complete ───────────┤
  │                                    │
  ├──── Enable Adv (0x2039) ─────────>│
  │<───── Command Complete ───────────┤
  │                                    │
  │                                 [开始广播]
  │                                    │

8.2 连接建立时序

复制代码
时间戳: 15:52:30 (示例)

1. 中心设备发起连接
   控制器收到连接请求

2. LE Meta Event - Connection Complete
   [RX]: 04 3e 13 01 00 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
   解析:
   - 04: HCI Event Packet
   - 3e: LE Meta Event
   - 13: Parameter Length (19 bytes)
   - 01: Subevent Code (LE Connection Complete)
   - 00: Status (Success)
   - XX XX: Connection Handle
   - 01: Role (0=Master, 1=Slave)
   - XX: Peer Address Type
   - XX XX XX XX XX XX: Peer Address
   - XX XX: Conn Interval
   - XX XX: Conn Latency
   - XX XX: Supervision Timeout
   - XX: Master Clock Accuracy

3. GAP层处理
   [I] BLE : CNNS idx=0 role=1 hdl=0001
   → 连接建立: 索引0, 角色为Slave, 句柄0x0001

4. 加载GATT缓存
   app_ble_check_load_server_cache()
   app_ble_check_load_client_cache()

5. 应用层通知
   BLE_LINK_CONNECTED_EVENT
   DP_CONN_DONE: conidx=0x0

6. MTU交换
   客户端发起MTU Exchange Request
   [RX]: ATT_EXCHANGE_MTU_REQ mtu=XXX

   服务端响应
   [TX]: ATT_EXCHANGE_MTU_RSP mtu=247

   MTU Exchange Complete
   [I] BLE : MTU Exchanged: conidx=0 mtu=247

7. 服务发现(可选)
   客户端读取Primary Service
   客户端读取Characteristic

8. CCCD写入
   客户端使能通知
   [RX]: ATT_WRITE_REQ handle=CCCD value=0x0001

   [I] BLE : DP_CCC_CHANGED conidx=0

   连接就绪,可以开始数据传输

完整时序图:

复制代码
外设(从设备)                              中心设备(主设备)
     │                                         │
     ├──────── Advertising ──────────────────>│
     │                                         │
     │<──────── Scan Request ─────────────────┤
     ├──────── Scan Response ────────────────>│
     │                                         │
     │<──────── Connect Request ──────────────┤
     │                                         │
  [连接建立]                               [连接建立]
     │                                         │
     │<──────── MTU Exchange Req ─────────────┤
     ├──────── MTU Exchange Rsp ─────────────>│
     │                                         │
     │<──────── Discover Services ────────────┤
     ├──────── Service List ─────────────────>│
     │                                         │
     │<──────── Discover Chars ───────────────┤
     ├──────── Char List ────────────────────>│
     │                                         │
     │<──────── Write CCCD(0x0001) ───────────┤
     ├──────── Write Response ───────────────>│
     │                                         │
  [就绪状态]                              [就绪状态]
     │                                         │
     ├──────── Notification ─────────────────>│
     │                                         │
     │<──────── Write Request ────────────────┤
     ├──────── Write Response ───────────────>│
     │                                         │

8.3 数据传输时序

8.3.1 通知(Notification)传输
复制代码
外设                                   中心设备
  │                                      │
  ├────── ATT Handle Value Ntf ────────>│
  │       (无需响应)                      │
  │                                      │
  ├────── ATT Handle Value Ntf ────────>│
  │                                      │
  ├────── ATT Handle Value Ntf ────────>│
  │                                      │

数据包格式:

复制代码
┌──────┬────────┬─────────┬──────────┐
│ 0x1B │ Handle │  Value  │          │
│ (Ntf)│(2 byte)│(N bytes)│          │
└──────┴────────┴─────────┴──────────┘
8.3.2 写入(Write)传输
复制代码
外设                                   中心设备
  │                                      │
  │<────── ATT Write Request ───────────┤
  │        Handle + Value                │
  ├────── ATT Write Response ──────────>│
  │        (0x13)                         │
  │                                      │
  │<────── ATT Write Command ───────────┤
  │        (无需响应)                      │
  │                                      │

8.4 断连时序

复制代码
时间戳: 15:49:51:599 (从日志分析)

1. 上层协议断连
   HFP断连:
   [RX]: 02 82 20 08 00 04 00 40 30 21 53 01 49
   → RFCOMM DISC命令 (dlci=8)

   [TX]: 02 82 20 08 00 04 00 55 00 21 73 01 63
   → RFCOMM UA响应

2. AVRCP断连
   [I] BLE : AVRCP_EVENT_DISCONNECT

3. A2DP断连
   [I] BLE : A2DP_EVENT_STREAM_CLOSED

4. L2CAP通道关闭
   各个PSM通道依次关闭

5. ACL链路断开(如果完全断连)
   [RX]: 04 05 04 XX XX XX XX
   → HCI Disconnection Complete Event

6. BLE连接断开(如果有)
   [I] BLE : GAP_CONN_EVENT_CLOSED
   conidx=X reason=0x13 (Remote User Terminated)

7. 清理资源
   - 释放连接信息
   - 重置状态变量
   - 通知应用层

8. 恢复广播(如果需要)
   ui_ble_chargebox_refresh_adv()
   → 启动快速广播(30ms间隔)

8.8 CTKD跨传输密钥派生机制

8.8.1 CTKD定义与应用场景

CTKD (Cross-Transport Key Derivation) 是蓝牙核心规范v4.1引入的一种跨传输密钥派生机制,允许双模设备(同时支持BR/EDR和BLE)在一个传输层(如BLE)上建立的安全密钥派生出另一个传输层(如BR/EDR)的密钥,从而实现:

  • 无缝跨传输切换: 用户只需配对一次,即可在BR/EDR和BLE之间自由切换
  • 简化配对流程: 避免在两个传输层分别进行配对
  • 增强用户体验: 支持统一的设备身份标识和安全上下文

典型应用场景:

  • 耳机设备通过BLE完成快速配对,然后自动建立BR/EDR连接用于音频传输
  • 智能手表通过BLE进行数据同步,通过BR/EDR进行音频通话
  • 键盘/鼠标等输入设备在BLE低功耗模式和BR/EDR高速模式间切换
8.8.2 CTKD密钥派生原理

CTKD基于蓝牙安全管理器(SMP)的密钥分发机制,使用h4函数进行密钥派生:

密钥派生公式 (Bluetooth Core Spec v5.3, Vol 3, Part H, Section 2.4.2.5):

复制代码
BR/EDR Link Key = h4(LTK, "lebr")
  其中:
  - h4: CMAC-AES-128加密函数
  - LTK: BLE配对时生成的Long Term Key (128位)
  - "lebr": 4字节标识符,表示从LE到BR/EDR的派生

派生流程:

复制代码
┌──────────────────────────────────────────────────────────────┐
│                    CTKD密钥派生流程                          │
└──────────────────────────────────────────────────────────────┘

阶段1: BLE配对与密钥交换
┌────────────┐                                 ┌────────────┐
│  BLE主设备 │                                 │  BLE从设备 │
└────────────┘                                 └────────────┘
     │                                               │
     ├───── SMP Pairing Request ───────────────────>│
     │      (init_key_dist |= GAP_KDIST_LINKKEY)   │
     │                                               │
     │<───── SMP Pairing Response ──────────────────┤
     │      (resp_key_dist |= GAP_KDIST_LINKKEY)   │
     │                                               │
     ├───── SMP Pairing Confirm ───────────────────>│
     │                                               │
     │<───── SMP Pairing Random ────────────────────┤
     │                                               │
     ├───── SMP Encryption Information ────────────>│
     │      (分发LTK)                                │
     │                                               │

阶段2: Link Key派生与分发
     │                                               │
     │      本地计算:                                │
     │      BR_EDR_LK = h4(LTK, "lebr")             │
     │                                               │
     ├───── SMP Link Key Distribution ─────────────>│
     │      (分发派生的BR/EDR Link Key)              │
     │                                               │
     │<───── SMP Link Key Distribution ─────────────┤
     │      (对端也分发其派生的Link Key)             │
     │                                               │

阶段3: BR/EDR连接复用派生密钥
     │                                               │
     │      使用派生的Link Key建立BR/EDR安全连接     │
     │      无需重新配对                             │
     │                                               │
     ├═══ BR/EDR ACL Connection (with Link Key) ═══>│
     │                                               │

h4函数实现 (CMAC-AES-128):

c 复制代码
/**
 * @brief CTKD h4函数 - 派生BR/EDR Link Key
 *
 * @param ltk       输入的BLE LTK (128位)
 * @param keyID     标识符 "lebr" (4字节)
 * @param link_key  输出的BR/EDR Link Key (128位)
 *
 * 算法: link_key = AES-CMAC(ltk, keyID)
 */
static void ctkd_h4_derive_link_key(const uint8_t *ltk,
                                     const char *keyID,
                                     uint8_t *link_key)
{
    // keyID = "lebr" for LE to BR/EDR
    // keyID = "brle" for BR/EDR to LE

    // CMAC-AES-128计算
    aes_cmac_calculate(ltk, 16, keyID, 4, link_key);
}
8.8.3 CTKD密钥分发标志

在SMP配对过程中,通过设置GAP_KDIST_LINKKEY标志来指示支持CTKD:

c 复制代码
/// bthost/adapter/inc/ble/common/ble_core_common.h:381-396
/// Key Distribution Flags
enum gap_kdist
{
    /// No Keys to distribute
    GAP_KDIST_NONE    = 0x00,

    /// Encryption key (LTK) in distribution
    GAP_KDIST_ENCKEY  = (1 << 0),  // 0x01

    /// IRK (Identity Resolving Key) in distribution
    GAP_KDIST_IDKEY   = (1 << 1),  // 0x02

    /// CSRK (Connection Signature Resolving Key) in distribution
    GAP_KDIST_SIGNKEY = (1 << 2),  // 0x04

    /// Link Key (BR/EDR Link Key) in distribution - CTKD标志
    GAP_KDIST_LINKKEY = (1 << 3),  // 0x08

    GAP_KDIST_LAST    = (1 << 4)   // 0x10
};

密钥分发组合示例:

场景 init_key_dist resp_key_dist 说明
标准BLE配对 `ENCKEY IDKEY` `ENCKEY
CTKD完整支持 `ENCKEY IDKEY LINKKEY`
仅初始方分发 `ENCKEY LINKKEY` ENCKEY
8.8.4 CTKD代码实现示例
8.8.4.1 CTKD使能配置

编译时配置 (bthost/adapter/inc/bt/common/bt_sys_config.h:109-111):

c 复制代码
#ifdef BLE_ONLY_ENABLED
    #undef __GATT_OVER_BR_EDR__
    #undef CTKD_ENABLE              // BLE-only模式禁用CTKD
    #undef IS_CTKD_OVER_BR_EDR_ENABLED
#endif

运行时检查宏 (bthost/service/ble_app_new/src/ble_demo_app.c:41):

c 复制代码
// 检查设备是否支持CTKD: 比较BLE地址与BR/EDR地址是否相同
#define IS_CTKD_SUPPORT() \
    (memcmp(p_demo_app_info->app_demo_addr.address, \
            gap_hci_bt_address(), \
            sizeof(bt_bdaddr_t)) == 0)
8.8.4.2 SMP配对需求设置

在配对过程中动态设置CTKD标志 (bthost/service/ble_app_new/src/app_ble.c:3785-3807):

c 复制代码
static void app_ble_smp_get_requirements(uint16_t connhdl,
                                          smp_requirements_t *p_requirements)
{
    ble_global_t *g = ble_get_global();

#if defined(CTKD_ENABLE)
    uint8_t key_dist = 0;

    // 1. 检查是否有回调函数自定义密钥分发
    if (g->dist_lk_set_cb == NULL)
    {
        // 默认启用CTKD: 分发Link Key
        key_dist = GAP_KDIST_LINKKEY;
    }
    else
    {
        // 应用层回调决定是否分发Link Key
        key_dist |= g->dist_lk_set_cb();
    }

    // 2. 根据key_dist设置init和resp的分发标志
    if (key_dist & GAP_KDIST_LINKKEY)
    {
        // 主设备和从设备都分发Link Key
        p_requirements->init_key_dist |= GAP_KDIST_LINKKEY;
        p_requirements->resp_key_dist |= GAP_KDIST_LINKKEY;
    }
    else
    {
        // 移除Link Key分发标志
        p_requirements->init_key_dist &= ~GAP_KDIST_LINKKEY;
        p_requirements->resp_key_dist &= ~GAP_KDIST_LINKKEY;
    }
#endif

    // 3. 应用层可进一步修改SMP需求
    if (g->ble_smp_require_modify != NULL)
    {
        g->ble_smp_require_modify(conn->connhdl,
                                  (ble_smp_require_t *)p_requirements);
    }
}
8.8.4.3 针对iOS设备的CTKD处理

iOS设备对CTKD有特殊要求,需要动态调整 (bthost/service/ble_app_new/src/ble_demo_app.c:387-396):

c 复制代码
static void ble_demo_app_smp_requirement_modify_handler(uint16_t connhdl,
                                                          ble_smp_require_t *p_requirements)
{
    gap_conn_item_t *conn = gap_get_conn_item(connhdl);

    if (conn == NULL) return;

    // 如果设备不是iOS设备,且不支持CTKD over BR/EDR,移除Link Key分发
    // 这样可以确保LE Audio设备能通过其他方法进行CTKD
    if ((conn->adv_handle == p_demo_app_info->adv_hdl) &&
        (IS_IOS_DEV(conn->con_idx) == 0) &&  // 非iOS设备
        (IS_CTKD_SUPPORT() == 0))             // 不支持CTKD
    {
        TRACE(1, "adv hdl:%d smp requirements modify", conn->adv_handle);

        // 移除Link Key分发标志
        p_requirements->init_key_dist &= ~GAP_KDIST_LINKKEY;
        p_requirements->resp_key_dist &= ~GAP_KDIST_LINKKEY;
    }
}
8.8.4.4 CTKD密钥存储结构

密钥安全存储结构 (bthost/adapter/inc/adapter_service/gap_service.h:899-922):

c 复制代码
/// BLE配对安全信息结构
typedef struct
{
    // 配对级别 (Unauthenticated/Authenticated/Secure Connection)
    uint8_t pairing_lvl;

    // 密钥分发标志位
    uint8_t local_ltk_distributed: 1;   // 本地LTK已分发
    uint8_t local_irk_distributed: 1;   // 本地IRK已分发
    uint8_t local_csrk_distributed: 1;  // 本地CSRK已分发
    uint8_t peer_ltk_distributed: 1;    // 对端LTK已分发
    uint8_t peer_irk_distributed: 1;    // 对端IRK已分发
    uint8_t peer_csrk_distributed: 1;   // 对端CSRK已分发

    // 对端密钥
    uint8_t peer_irk[GAP_KEY_LEN];      // 16字节IRK
    uint8_t peer_csrk[GAP_KEY_LEN];     // 16字节CSRK

    // 加密密钥
    uint8_t ltk[GAP_KEY_LEN];           // 16字节LTK (用于派生Link Key)
    uint8_t local_ltk[GAP_KEY_LEN];     // 16字节本地LTK

    // 随机数和EDIV (Legacy Pairing使用)
    uint8_t rand[GAP_RAND_LEN];         // 8字节随机数
    uint8_t local_rand[GAP_RAND_LEN];   // 8字节本地随机数
    uint8_t ediv[GAP_EDIV_LEN];         // 2字节EDIV
    uint8_t local_ediv[GAP_EDIV_LEN];   // 2字节本地EDIV

    // 加密密钥长度 (7-16字节)
    uint8_t enc_key_size;
} gap_bond_sec_t;

/// 连接信息结构
typedef struct
{
    // ... 其他连接信息 ...

    // CTKD相关
    uint8_t ctkd_enc_key_size;          // CTKD加密密钥长度
    uint8_t *link_key;                  // 指向派生的BR/EDR Link Key (16字节)
    gap_bond_sec_t sec;                 // 绑定安全信息

} gap_conn_item_t;
8.8.4.5 CTKD与GATT over BR/EDR集成

CTKD常与GATT over BR/EDR结合使用 (bthost/service/common/besmain.cpp:769-982):

c 复制代码
static void bt_stack_config(void)
{
    // 1. 使能LE主机支持
    uint8_t le_host_support[] = {
#ifdef BLE_HOST_SUPPORT
        1,  // LE Host Support
#else
        0,
#endif
        0   // Simultaneous LE and BR/EDR to Same Device Capable
    };

    // 2. 使能Secure Connections (CTKD需要)
    uint8_t sec_conn_host_supp[] = {
#if BLE_AUDIO_ENABLED || (defined(CTKD_ENABLE) && defined(IS_CTKD_OVER_BR_EDR_ENABLED))
        1,  // Secure Connections Host Support
#else
        0,
#endif
    };

    // 3. L2CAP配置 - 使能SMP over BR/EDR
    bt_l2cap_config_t l2cap_cfg = {
#if defined(__GATT_OVER_BR_EDR__)
        .gatt_over_br_edr = true,        // GATT over BR/EDR
#endif
#if defined(__HFP_ACS_BV17_I__) || \
    (defined(CTKD_ENABLE) && defined(IS_CTKD_OVER_BR_EDR_ENABLED))
        .smp_over_br_edr = true,         // SMP over BR/EDR (CTKD需要)
#endif
    };

    l2cap_config_set(&l2cap_cfg);
}
8.8.5 CTKD完整时序图

以下时序图展示了CTKD从BLE配对到BR/EDR连接建立的完整过程:

复制代码
┌──────────────────────────────────────────────────────────────────────────┐
│              CTKD完整流程: BLE配对 → 密钥派生 → BR/EDR连接               │
└──────────────────────────────────────────────────────────────────────────┘

设备A (Central/Master)                               设备B (Peripheral/Slave)
 BLE PHY                                                BLE PHY
    │                                                      │
    │                                                      │
════════════════════ 阶段1: BLE广播与连接建立 ═══════════════════
    │                                                      │
    │              <──── ADV_IND ────                     │
    │                   (BLE可连接广播)                   │
    │                                                      │
    ├──────── CONNECT_IND ────────────────────────────────>│
    │         (发起BLE连接)                               │
    │                                                      │
    │<──────── LE Connection Complete ────────────────────┤
    │          (connHandle=0x0040, interval=24, latency=0)│
    │                                                      │
════════════════════ 阶段2: SMP配对与密钥协商 ═══════════════════
    │                                                      │
    │── SMP: Pairing Request ──────────────────────────────>│
    │   IO Capability: NoInputNoOutput                    │
    │   Auth Req: Bonding, MITM=0, SC=1                   │
    │   init_key_dist: ENCKEY|IDKEY|LINKKEY (0x0B)       │
    │                                                      │
    │<─ SMP: Pairing Response ─────────────────────────────┤
    │   IO Capability: DisplayYesNo                       │
    │   Auth Req: Bonding, MITM=1, SC=1                   │
    │   resp_key_dist: ENCKEY|IDKEY|LINKKEY (0x0B)       │
    │                                                      │
    ├─ SMP: Pairing Public Key (P-256) ───────────────────>│
    │                                                      │
    │<─ SMP: Pairing Public Key (P-256) ───────────────────┤
    │                                                      │
    │  [双方计算DHKey = P-256(local_private, peer_public)]│
    │                                                      │
    ├─ SMP: Pairing Confirm ──────────────────────────────>│
    │  Confirm = f4(PKa, PKb, Na, 0)                      │
    │                                                      │
    │<─ SMP: Pairing Confirm ──────────────────────────────┤
    │  Confirm = f4(PKa, PKb, Nb, 0)                      │
    │                                                      │
    ├─ SMP: Pairing Random ───────────────────────────────>│
    │  Random Value = Na                                   │
    │                                                      │
    │<─ SMP: Pairing Random ───────────────────────────────┤
    │  Random Value = Nb                                   │
    │                                                      │
    │  [验证Confirm值是否匹配]                             │
    │                                                      │
    ├─ SMP: Pairing DHKey Check ──────────────────────────>│
    │  Ea = f6(MacKey, Na, Nb, rb, IOcapA, A, B)          │
    │                                                      │
    │<─ SMP: Pairing DHKey Check ──────────────────────────┤
    │  Eb = f6(MacKey, Nb, Na, ra, IOcapB, B, A)          │
    │                                                      │
    │  [配对成功, 生成LTK = f5(DHKey, Na, Nb, A, B)]      │
    │                                                      │
════════════════════ 阶段3: 密钥分发 (含CTKD) ═══════════════════
    │                                                      │
    ├─ SMP: Encryption Information ───────────────────────>│
    │  LTK (128-bit Long Term Key)                        │
    │                                                      │
    ├─ SMP: Master Identification ────────────────────────>│
    │  EDIV=0x0000, Rand=0x0000000000000000               │
    │  (SC配对下EDIV和Rand均为0)                          │
    │                                                      │
    ├─ SMP: Identity Information ─────────────────────────>│
    │  IRK (128-bit Identity Resolving Key)               │
    │                                                      │
    ├─ SMP: Identity Address Information ─────────────────>│
    │  Address Type: Public/Random Static                 │
    │  Address: XX:XX:XX:XX:XX:XX                         │
    │                                                      │
    ├─ SMP: Signing Information ──────────────────────────>│
    │  CSRK (128-bit Connection Signature Resolving Key)  │
    │                                                      │
    │  *** CTKD密钥派生 ***                                │
    │  [本地计算: BR_Link_Key = h4(LTK, "lebr")]          │
    │                                                      │
    ├─ SMP: Link Key (CTKD) ──────────────────────────────>│
    │  派生的BR/EDR Link Key (128-bit)                     │
    │  用于后续BR/EDR连接认证                             │
    │                                                      │
    │<─ SMP: Encryption Information ───────────────────────┤
    │   对端的LTK                                          │
    │                                                      │
    │<─ SMP: Master Identification ────────────────────────┤
    │   EDIV=0x0000, Rand=0x0000000000000000              │
    │                                                      │
    │<─ SMP: Identity Information ─────────────────────────┤
    │   对端的IRK                                          │
    │                                                      │
    │<─ SMP: Identity Address Information ─────────────────┤
    │   对端的Identity Address                             │
    │                                                      │
    │<─ SMP: Signing Information ──────────────────────────┤
    │   对端的CSRK                                         │
    │                                                      │
    │   [本地计算: BR_Link_Key = h4(peer_LTK, "lebr")]    │
    │                                                      │
    │<─ SMP: Link Key (CTKD) ──────────────────────────────┤
    │   对端派生的BR/EDR Link Key                          │
    │                                                      │
    │  [存储所有密钥到NV存储]                              │
    │  gap_nv_add_ble_device(conn, &bond_sec);            │
    │                                                      │
════════════════════ 阶段4: BR/EDR连接建立 (使用CTKD密钥) ═══════
    │                                                      │
 BR/EDR PHY                                            BR/EDR PHY
    │                                                      │
    ├──── Page (使用相同的BD Address) ────────────────────>│
    │                                                      │
    │<──── Page Response ──────────────────────────────────┤
    │                                                      │
    ├──── LMP Authentication Request ─────────────────────>│
    │     (使用CTKD派生的Link Key进行认证)                │
    │                                                      │
    │<──── LMP Authentication Response ────────────────────┤
    │                                                      │
    │  [Challenge-Response认证成功]                        │
    │  [无需重新配对!]                                     │
    │                                                      │
    ├══ BR/EDR ACL Connection Established ════════════════>│
    │   Connection Handle: 0x0001                          │
    │   Encryption Enabled: Yes (使用派生的Link Key)      │
    │                                                      │
════════════════════ 阶段5: GATT over BR/EDR (可选) ═════════════
    │                                                      │
    │── L2CAP: Connection Request (PSM=0x001F) ───────────>│
    │   (ATT over BR/EDR)                                 │
    │                                                      │
    │<─ L2CAP: Connection Response ────────────────────────┤
    │   CID=0x0040 Allocated                              │
    │                                                      │
    │── ATT: Exchange MTU Request ─────────────────────────>│
    │                                                      │
    │<─ ATT: Exchange MTU Response ────────────────────────┤
    │                                                      │
    │  [GATT服务发现和数据传输...]                         │
    │                                                      │

时序关键点说明:

  1. init_key_dist和resp_key_dist包含LINKKEY标志 (0x0B = 0x01|0x02|0x08)
  2. h4派生函数 : BR_Link_Key = AES-CMAC(LTK, "lebr")
  3. 双向密钥分发: 主从设备都分发各自派生的Link Key
  4. BR/EDR认证无需用户交互: 直接使用派生的Link Key进行Challenge-Response认证
  5. 密钥长度: 所有密钥均为128位 (16字节)
8.8.6 CTKD实际操作例程
例程1: 使能CTKD并设置SMP参数
c 复制代码
// 1. 在应用层注册CTKD使能回调
uint8_t app_ctkd_link_key_dist_callback(void)
{
    // 检查设备是否支持双模
    if (bt_is_dual_mode_device())
    {
        return GAP_KDIST_LINKKEY;  // 返回Link Key分发标志
    }
    return 0;  // 单模设备不分发Link Key
}

void app_ble_init(void)
{
    ble_global_t *g = ble_get_global();

    // 注册CTKD密钥分发回调
    g->dist_lk_set_cb = app_ctkd_link_key_dist_callback;

    // 设置Secure Connections要求 (CTKD需要)
    g->default_smp_requirements.auth_req |= SMP_AUTH_SEC_CON;

    // 设置默认密钥分发 (含CTKD)
    g->default_smp_requirements.init_key_dist =
        GAP_KDIST_ENCKEY |   // LTK
        GAP_KDIST_IDKEY |    // IRK
        GAP_KDIST_LINKKEY;   // BR/EDR Link Key (CTKD)

    g->default_smp_requirements.resp_key_dist =
        GAP_KDIST_ENCKEY |
        GAP_KDIST_IDKEY |
        GAP_KDIST_LINKKEY;
}
例程2: 处理CTKD密钥接收事件
c 复制代码
static void app_ble_handle_link_key_received(uint16_t connhdl,
                                               const uint8_t *link_key)
{
    gap_conn_item_t *conn = gap_get_conn_item(connhdl);

    if (conn == NULL) return;

    // 1. 分配Link Key存储空间
    if (conn->link_key == NULL)
    {
        conn->link_key = (uint8_t *)malloc(GAP_KEY_LEN);
    }

    // 2. 保存接收到的Link Key
    memcpy(conn->link_key, link_key, GAP_KEY_LEN);

    // 3. 记录CTKD密钥长度
    conn->ctkd_enc_key_size = conn->sec.enc_key_size;

    TRACE(2, "[CTKD] Link Key received for connhdl=0x%04x, key_size=%d",
          connhdl, conn->ctkd_enc_key_size);

    // 4. 可选: 触发BR/EDR连接
    if (app_should_establish_bredr_connection())
    {
        bt_bdaddr_t *peer_addr = &conn->peer.peer_addr.addr;
        app_bt_start_bredr_connection(peer_addr);
    }
}
例程3: 使用CTKD密钥建立BR/EDR连接
c 复制代码
void app_bt_establish_bredr_with_ctkd(const bt_bdaddr_t *peer_addr)
{
    // 1. 从NV存储中获取CTKD密钥
    gap_bredr_sec_t bredr_sec;
    if (!nv_get_bt_device_by_addr(peer_addr, &bredr_sec))
    {
        TRACE(0, "[CTKD] No Link Key found, pairing required");
        return;
    }

    // 2. 验证Link Key是否有效
    if (bredr_sec.link_key_present)
    {
        TRACE(1, "[CTKD] Using derived Link Key, key_size=%d",
              bredr_sec.link_key_size);

        // 3. 使用存储的Link Key建立BR/EDR连接
        bt_create_connection_param_t param = {
            .bd_addr = *peer_addr,
            .use_stored_link_key = true,
            .link_key = bredr_sec.link_key,
            .link_key_size = bredr_sec.link_key_size,
        };

        btif_me_create_acl_connection(&param);
    }
    else
    {
        TRACE(0, "[CTKD] Link Key not present");
    }
}
例程4: CTKD日志分析示例

以下是一次完整的CTKD配对日志:

复制代码
[15:49:50.123] [I] BLE: SMP Pairing Request sent
[15:49:50.125]     IO Cap: NoInputNoOutput
[15:49:50.126]     Auth Req: Bonding|SC (0x0D)
[15:49:50.127]     Init Key Dist: ENCKEY|IDKEY|LINKKEY (0x0B)
[15:49:50.128]     Resp Key Dist: ENCKEY|IDKEY|LINKKEY (0x0B)

[15:49:50.234] [I] BLE: SMP Pairing Response received
[15:49:50.235]     IO Cap: DisplayYesNo
[15:49:50.236]     Auth Req: Bonding|MITM|SC (0x0D)

[15:49:50.456] [I] BLE: SMP Public Key Exchange Complete
[15:49:50.457]     DHKey Calculated

[15:49:50.678] [I] BLE: SMP Pairing Confirm OK
[15:49:50.789] [I] BLE: SMP Pairing Random OK
[15:49:50.890] [I] BLE: SMP DHKey Check OK

[15:49:50.991] [I] BLE: SMP LTK Generated
[15:49:50.992]     LTK: A1 B2 C3 D4 E5 F6 G7 H8 I9 J0 K1 L2 M3 N4 O5 P6

[15:49:51.100] [I] BLE: SMP Key Distribution Phase
[15:49:51.102] [I] BLE: Encryption Information Sent (LTK)
[15:49:51.105] [I] BLE: Identity Information Sent (IRK)
[15:49:51.108] [I] BLE: Identity Address: Public 11:22:33:44:55:66

[15:49:51.200] [I] BLE: **CTKD Key Derivation**
[15:49:51.201]     Input LTK:  A1 B2 C3 D4 E5 F6 ...
[15:49:51.202]     h4("lebr"): ...
[15:49:51.203]     BR Link Key: 12 34 56 78 9A BC DE F0 ...

[15:49:51.250] [I] BLE: Link Key Sent (CTKD)
[15:49:51.251]     Link Key: 12 34 56 78 9A BC DE F0 ...

[15:49:51.350] [I] BLE: Pairing Complete
[15:49:51.351]     Pairing Level: Secure Connection (0x0C)
[15:49:51.352]     Bonded: Yes
[15:49:51.353]     CTKD Enabled: Yes

[15:49:52.000] [I] BT: BR/EDR Connection Request
[15:49:52.001]     Peer Address: 11:22:33:44:55:66
[15:49:52.002]     Using CTKD Link Key

[15:49:52.100] [I] BT: Authentication Request
[15:49:52.101]     Challenge: XX XX XX XX ...
[15:49:52.102]     Response: YY YY YY YY ...
[15:49:52.103]     Result: Success (无需用户交互!)

[15:49:52.200] [I] BT: BR/EDR Connection Established
[15:49:52.201]     Handle: 0x0001
[15:49:52.202]     Encryption: Enabled
[15:49:52.203]     Link Key Type: CTKD Derived
8.8.7 CTKD常见问题排查
问题现象 可能原因 排查方法
SMP配对时未分发Link Key GAP_KDIST_LINKKEY标志未设置 检查init_key_distresp_key_dist
BR/EDR连接需要重新配对 Link Key未正确存储或派生失败 检查NV存储中的Link Key字段
iOS设备CTKD失败 iOS对CTKD有特殊要求 使用IS_IOS_DEV()判断并特殊处理
双模地址不一致 BLE和BR/EDR使用不同地址 确保IS_CTKD_SUPPORT()返回true
h4派生失败 LTK无效或加密库未正确初始化 检查LTK值和AES-CMAC实现

调试命令:

c 复制代码
// 打印CTKD状态
void app_ctkd_dump_status(uint16_t connhdl)
{
    gap_conn_item_t *conn = gap_get_conn_item(connhdl);

    TRACE(0, "=== CTKD Status ===");
    TRACE(1, "CTKD Enabled: %d", IS_CTKD_SUPPORT());
    TRACE(1, "Link Key Present: %d", (conn->link_key != NULL));
    TRACE(1, "Key Size: %d", conn->ctkd_enc_key_size);
    TRACE(1, "Pairing Level: 0x%02x", conn->sec.pairing_lvl);

    if (conn->link_key)
    {
        DUMP8("Link Key: ", conn->link_key, GAP_KEY_LEN);
    }
}

9. 常见问题与调试

9.1 广播问题

问题1: 广播无法启动

可能原因:

  1. adv_force_disabled 标志被设置
  2. BLE连接数已达上限
  3. 处于从耳角色
  4. HCI命令返回错误

调试方法:

c 复制代码
// 检查广播是否被允许
bool ble_adv_is_allowed(void)
{
    if (!gap_stack_is_ready()) {
        return false;
    }
    if (ble_get_global()->adv_force_disabled) {
        return false;
    }
    if (app_is_arrive_at_max_ble_connections()) {
        return false;
    }
    return true;
}

问题2: 广播间隔不正确

检查:

  • 是否设置了正确的间隔参数
  • 定时器是否正常工作
  • 状态机是否正确切换

9.2 连接问题

问题1: 连接后立即断开

可能原因:

  1. 连接参数不兼容
  2. MTU交换失败
  3. 安全要求不匹配
  4. 控制器资源不足

问题2: 无法收到数据

检查:

  1. CCCD是否正确配置
  2. MTU大小是否足够
  3. 回调函数是否正确注册
  4. 数据包格式是否正确

9.3 日志分析技巧

关键日志标记:

  • CNNS: Connection Started
  • CNNE: Connection Ended
  • FADV: Force ADV (广播强制操作)
  • FDIS: Force Disable
  • MTUE: MTU Exchanged
  • DP_CONN_DONE: Datapath连接完成
  • DP_DISCONN_DONE: Datapath断连完成

HCI事件码:

  • 04 0e: HCI Command Complete
  • 04 3e: HCI LE Meta Event
  • 04 05: HCI Disconnection Complete
  • 04 13: HCI Number of Completed Packets

10. 性能优化建议

10.1 功耗优化

  1. 广播间隔优化

    • 连接前: 30ms快速广播(10秒) → 480ms慢速广播
    • 已连接: 停止广播
    • 建议根据实际场景调整时长
  2. 连接参数优化

    • 空闲时使用大连接间隔(400×1.25ms = 500ms)
    • 数据传输时使用小连接间隔(12×1.25ms = 15ms)
    • 根据场景动态调整
  3. PHY选择

    • LE 1M: 平衡功耗和速率
    • LE 2M: 高速传输,略高功耗
    • LE Coded: 长距离,高功耗

10.2 吞吐量优化

  1. 增大MTU

    c 复制代码
    // 请求最大MTU
    gap_request_mtu_exchange(connhdl, 247);  // 最大247字节
  2. 使用连接事件长度扩展

    c 复制代码
    // 增加连接事件长度以传输更多数据包
    gap_set_conn_event_length(connhdl, max_ce_length);
  3. 批量传输

    c 复制代码
    // 在单个连接事件中发送多个通知
    for (int i = 0; i < batch_count; i++) {
        gatts_send_notification(connhdl, char_handle, data[i], len[i]);
    }

10.3 稳定性优化

  1. 错误处理

    c 复制代码
    // 所有HCI命令都应检查返回状态
    bt_status_t status = gap_start_advertising(&params);
    if (status != BT_STS_SUCCESS) {
        LOG("Adv start failed: %d", status);
        // 错误恢复逻辑
    }
  2. 超时机制

    c 复制代码
    // 连接超时检测
    os_timer_start(conn_timeout_timer, CONN_TIMEOUT_MS);
  3. 状态同步

    c 复制代码
    // 确保状态一致性
    if (ble_handle->connected != gap_is_connected(conidx)) {
        LOG("State mismatch detected, syncing...");
        ble_handle->connected = gap_is_connected(conidx);
    }

11. 硬件RF层与物理层深度解析

11.1 RF配置和功率控制

BES芯片支持精细的RF功率控制,用于优化功耗和通信距离:

RF配置结构 (bt_drv_interface.h:250-275):

c 复制代码
/// BT driver customer RF config structure
struct btdrv_customer_rf_config_t
{
    bool config_xtal_en;          // 晶振配置使能
    bool config_tx_pwr_en;        // 发送功率配置使能
    uint16_t xtal_cap_val;        // 晶振电容值

    // BT Classic功率索引 (8级功率)
    int8_t bt_tx_idx7_pwr;        // BT TX 最高功率 (index 7)
    int8_t bt_tx_idx6_pwr;        // BT TX index 6
    int8_t bt_tx_idx5_pwr;        // BT TX index 5
    int8_t bt_tx_idx4_pwr;        // BT TX index 4
    int8_t bt_tx_idx3_pwr;        // BT TX index 3
    int8_t bt_tx_idx2_pwr;        // BT TX index 2
    int8_t bt_tx_idx1_pwr;        // BT TX index 1
    int8_t bt_tx_idx0_pwr;        // BT TX 最低功率 (index 0)

    // BLE功率索引 (8级功率)
    int8_t le_tx_idx7_pwr;        // LE TX 最高功率
    int8_t le_tx_idx6_pwr;
    int8_t le_tx_idx5_pwr;
    int8_t le_tx_idx4_pwr;
    int8_t le_tx_idx3_pwr;
    int8_t le_tx_idx2_pwr;
    int8_t le_tx_idx1_pwr;
    int8_t le_tx_idx0_pwr;        // LE TX 最低功率

    // 特殊场景功率
    int8_t bt_tx_page_pwr;        // Page扫描功率
    int8_t bt_tx_page_high_pwr;   // Page高功率模式
    int8_t bt_tx_max_pwr;         // BT最大功率
    int8_t le_tx_max_pwr;         // LE最大功率
};

功率控制接口:

c 复制代码
// 设置BDR/BLE发送功率
void btdrv_set_bdr_ble_txpower(uint8_t txpwr_idx, uint16_t n);

// 设置EDR发送功率
void btdrv_set_edr_txpower(uint8_t div, uint8_t power_level);

// 更新固定发送功率
void bt_drv_rf_update_fixed_tx_pwr(uint8_t Bt_Tx_Pwr_In_dB);
void ble_drv_rf_update_fixed_tx_pwr(uint8_t Ble_Tx_Pwr_In_dB);

// 高效功率控制
void bt_drv_rf_high_efficency_tx_pwr_ctrl(bool en, bool reset);

11.2 BT_CLK时钟单位和Slot机制

BT_CLK是蓝牙系统的核心时间基准:

时钟单位定义 (bt_drv_interface.h:116-122):

c 复制代码
// BT_CLK单位: 312.5us (Bluetooth Clock Unit)
#define BT_CLK_UNIT 312.5       // us
#define BT_CLK_UNIT_2X 625      // us (2倍时钟单位)
#define BT_CLK_UNIT_10X 3125    // us (10倍时钟单位)

// 时间单位转换宏
#define US_TO_BTCLKS(us)    ((uint64_t)(us) * 2 / BT_CLK_UNIT_2X)
#define BTCLKS_TO_US(n)     ((uint64_t)(n) * BT_CLK_UNIT_2X / 2)
#define HALF_SLOT_INV(x)    (HALF_SLOT_SIZE - (x) - 1)

Slot时间片概念:

复制代码
1 Slot = 625us = 2个BT_CLK = 1个时间单位
1 BT_CLK = 312.5us = 半个Slot

时间轴:
|--Slot 0--|--Slot 1--|--Slot 2--|--Slot 3--|
0         625       1250      1875      2500 (us)
|    TX   |    RX   |    TX   |    RX   |
Master    Slave     Master    Slave

时钟操作接口:

c 复制代码
// 获取当前BT时钟
uint32_t btdrv_syn_get_curr_ticks(void);

// 获取连接的BT时间
uint32_t bt_syn_get_curr_ticks(uint16_t conhdl);

// 获取时间偏移
int32_t bt_syn_get_offset_ticks(uint16_t conhdl);

// 时钟计数转换为微秒
int64_t btdrv_clkcnt_to_us(uint32_t clk, uint16_t cnt);

// 从从设备时钟转换为主设备时钟
int btdrv_slave2master_clkcnt_convert(uint32_t local_clk, uint16_t local_cnt,
                                       int32_t clk_offset, uint16_t bit_offset,
                                       uint32_t *master_clk, uint16_t *master_cnt);

11.3 物理层Packet类型

BT Classic支持多种数据包类型,用于不同的传输速率和可靠性需求:

Packet类型定义 (bt_drv_interface.h:174-201):

c 复制代码
/// Packet type code interpretation - BR (Basic Rate)
#define ID_NUL_TYPE     0x0     // NULL packet (无数据)
#define POLL_TYPE       0x1     // POLL packet (轮询)
#define FHS_TYPE        0x2     // Frequency Hop Synchronization (跳频同步)

// BR数据包 (1 Mbps)
#define DM1_TYPE        0x3     // Data Medium rate, 1-slot, FEC(2/3)
#define DH1_TYPE        0x4     // Data High rate, 1-slot, No FEC
#define DM3_TYPE        0xA     // Data Medium rate, 3-slot, FEC(2/3)
#define DH3_TYPE        0xB     // Data High rate, 3-slot, No FEC
#define DM5_TYPE        0xE     // Data Medium rate, 5-slot, FEC(2/3)
#define DH5_TYPE        0xF     // Data High rate, 5-slot, No FEC

// EDR数据包 (2/3 Mbps)
#define DH1_2_TYPE      0x4     // 2Mbps, 1-slot
#define DH1_3_TYPE      0x8     // 3Mbps, 1-slot
#define DH3_2_TYPE      0xA     // 2Mbps, 3-slot
#define DH3_3_TYPE      0xB     // 3Mbps, 3-slot
#define DH5_2_TYPE      0xE     // 2Mbps, 5-slot
#define DH5_3_TYPE      0xF     // 3Mbps, 5-slot

// SCO/eSCO数据包 (语音)
#define HV1_TYPE        0x5     // High quality Voice, 1-slot
#define HV2_TYPE        0x6     // High quality Voice, 2-slot
#define HV3_TYPE        0x7     // High quality Voice, 3-slot
#define EV3_TYPE        0x7     // Enhanced Voice, 3-slot
#define EV4_TYPE        0xC     // Enhanced Voice, 4-slot
#define EV5_TYPE        0xD     // Enhanced Voice, 5-slot
#define EV3_2_TYPE      0x6     // EV3 @ 2Mbps
#define EV3_3_TYPE      0x7     // EV3 @ 3Mbps
#define EV5_2_TYPE      0xC     // EV5 @ 2Mbps
#define EV5_3_TYPE      0xD     // EV5 @ 3Mbps

Packet有效载荷大小 (bt_drv_interface.h:203-228):

c 复制代码
// BR数据包大小 (字节)
#define DM1_PACKET_SIZE         17      // DM1: 17 bytes
#define DH1_PACKET_SIZE         27      // DH1: 27 bytes
#define DM3_PACKET_SIZE         121     // DM3: 121 bytes
#define DH3_PACKET_SIZE         183     // DH3: 183 bytes
#define DM5_PACKET_SIZE         224     // DM5: 224 bytes
#define DH5_PACKET_SIZE         339     // DH5: 339 bytes

// EDR数据包大小 (字节)
#define DH1_2_PACKET_SIZE       54      // DH1-2: 54 bytes
#define DH1_3_PACKET_SIZE       83      // DH1-3: 83 bytes
#define DH3_2_PACKET_SIZE       367     // DH3-2: 367 bytes
#define DH3_3_PACKET_SIZE       552     // DH3-3: 552 bytes
#define DH5_2_PACKET_SIZE       679     // DH5-2: 679 bytes
#define DH5_3_PACKET_SIZE       1021    // DH5-3: 1021 bytes (最大)

// SCO数据包大小 (字节)
#define HV1_PACKET_SIZE         10
#define HV2_PACKET_SIZE         20
#define HV3_PACKET_SIZE         30
#define EV3_PACKET_SIZE         30
#define EV4_PACKET_SIZE         120
#define EV5_PACKET_SIZE         180

Packet类型选择策略:

复制代码
吞吐量优先: DH5 > DH3 > DH1
可靠性优先: DM5 > DM3 > DM1 (带FEC纠错)
延迟优先: DH1 (单slot, 625us)
平衡模式: DH3 (3-slot, 1.875ms)

EDR模式:
- DH5_3: 1021字节/3.125ms = 326 KB/s (最大吞吐)
- DH3_2: 367字节/1.875ms = 196 KB/s

11.4 AFH自适应跳频

AFH (Adaptive Frequency Hopping) 用于避开干扰信道,提高通信质量:

LMP AFH命令 (bt_drv_interface.h:80-100):

c 复制代码
// LMP AFH相关Opcode
#define LMP_SET_AFH_OPCODE                60    // 设置AFH信道映射
#define LMP_CH_CLASS_REQ_EXTOPCODE        16    // 信道分类请求
#define LMP_CH_CLASS_EXTOPCODE            17    // 信道分类

// AFH信道映射
#define CHNL_MAP_LEN        0x0A               // 10字节信道映射
#define LE_CHNL_MAP_LEN     0x05               // LE: 5字节信道映射

AFH工作原理:

复制代码
BT Classic使用79个信道 (2.402 - 2.480 GHz)
信道间隔: 1 MHz
跳频速率: 1600 hops/sec

AFH机制:
1. 监测每个信道的质量 (RSSI, BER)
2. 将质量差的信道标记为"坏信道"
3. 更新AFH信道映射 (bitmap, 79 bits)
4. 仅在"好信道"中跳频
5. 至少保留20个可用信道

信道映射格式 (10字节):
Byte 0: Channel 0-7
Byte 1: Channel 8-15
...
Byte 9: Channel 72-78, Reserved[79-79]

示例:
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x7F
= 全部79个信道可用

BLE信道映射 (co_bt_defines.h:99-180):

c 复制代码
// BLE使用40个信道 (0-39)
// 数据信道: 0-36 (37个)
// 广播信道: 37, 38, 39 (3个)

#define DATA_CHANNEL_MIN    0
#define DATA_CHANNEL_MAX    36
#define DATA_CHANNEL_NB     37
#define ADV_CHANNEL_37      37      // 2402 MHz
#define ADV_CHANNEL_38      38      // 2426 MHz
#define ADV_CHANNEL_39      39      // 2480 MHz

// 最少使用信道数
#define DATA_CHANNEL_USED_NB_MIN    2

// 信道映射长度
#define LE_CHNL_MAP_LEN     0x05    // 5字节 (40 bits)

12. SMP安全管理与配对鉴权

12.1 SMP状态机 (26个Phase)

SMP (Security Manager Protocol) 状态机控制配对流程:

SMP Phase定义 (gap_i.h:232-260):

c 复制代码
typedef enum {
    SMP_PHASE_IDLE                          = 0x00,  // 空闲
    SMP_PHASE_PAIRING_START                 = 0x01,  // 配对开始
    SMP_PHASE_GEN_TK_RAND                   = 0x02,  // 生成TK/随机数
    SMP_PHASE_GEN_CFM_VALUE                 = 0x03,  // 生成Confirm值
    SMP_PHASE_WAIT_PAIRING_CONFIRM          = 0x04,  // 等待配对Confirm
    SMP_PHASE_WAIT_PAIRING_RANDOM           = 0x05,  // 等待配对Random
    SMP_PHASE_VERIFY_CONFIRM                = 0x06,  // 验证Confirm
    SMP_PHASE_GEN_STK                       = 0x07,  // 生成STK (Legacy)
    SMP_PHASE_GEN_PUB_KEY                   = 0x08,  // 生成公钥 (SC)
    SMP_PHASE_WAIT_PAIRING_PUBLIC_KEY       = 0x09,  // 等待对方公钥
    SMP_PHASE_GEN_DHKEY                     = 0x0a,  // 生成DHKey
    SMP_PHASE_GET_PASSKEY                   = 0x0b,  // 获取Passkey
    SMP_PHASE_GET_L_OOB_AUTH_DATA           = 0x0c,  // 获取本地OOB数据
    SMP_PHASE_GET_P_OOB_AUTH_DATA           = 0x0d,  // 获取对方OOB数据
    SMP_PHASE_GEN_RANDOM                    = 0x0e,  // 生成随机数
    SMP_PHASE_GEN_USER_VALUE                = 0x0f,  // 生成用户确认值
    SMP_PHASE_START_STAGE_2                 = 0x10,  // 开始阶段2
    SMP_PHASE_GEN_LTK                       = 0x11,  // 生成LTK
    SMP_PHASE_GEN_CHECK_VALUE               = 0x12,  // 生成Check值
    SMP_PHASE_WAIT_PAIRING_DHKEY_CHECK      = 0x13,  // 等待DHKey Check
    SMP_PHASE_VERIFY_CHECK                  = 0x14,  // 验证Check
    SMP_PHASE_WAIT_PEER_LTK_REQ             = 0x15,  // 等待LTK请求
    SMP_PHASE_WAIT_ENC_CHANGE               = 0x16,  // 等待加密变更
    SMP_PHASE_START_PHASE_3                 = 0x17,  // 开始阶段3 (密钥分发)
    SMP_PHASE_WAIT_DIST_KEY                 = 0x18,  // 等待密钥分发
    SMP_PHASE_FINISHED                      = 0x19,  // 配对完成
    SMP_PHASE_MAX_NUM                       = 0x1a,
} smp_phase_t;

SMP Opcode (gap_i.h:213-228):

c 复制代码
typedef enum {
    SMP_PAIRING_REQ             = 0x01,  // 配对请求
    SMP_PAIRING_RSP             = 0x02,  // 配对响应
    SMP_PAIRING_CONFIRM         = 0x03,  // 配对Confirm
    SMP_PAIRING_RANDOM          = 0x04,  // 配对Random
    SMP_PAIRING_FAILED          = 0x05,  // 配对失败
    SMP_ENCRYPTION_INFO         = 0x06,  // 加密信息 (LTK)
    SMP_CENTRAL_IDENTIFICATION  = 0x07,  // 中心设备标识 (EDIV, Rand)
    SMP_IDENTITY_INFO           = 0x08,  // 身份信息 (IRK)
    SMP_IDENTITY_ADDR_INFO      = 0x09,  // 身份地址信息
    SMP_SIGNING_INFO            = 0x0a,  // 签名信息 (CSRK)
    SMP_SECURITY_REQ            = 0x0b,  // 安全请求
    SMP_PAIRING_PUBLIC_KEY      = 0x0c,  // 配对公钥 (SC)
    SMP_PAIRING_DHKEY_CHECK     = 0x0d,  // DHKey Check (SC)
    SMP_PAIRING_KEYPRESS_NOTIFY = 0x0e,  // 按键通知
} smp_opcode_t;

SMP配对流程示例 (Legacy Pairing - Just Works):

复制代码
Initiator (Central)              Responder (Peripheral)
      |                                  |
      |------ Pairing Request -------->  | Phase 1: 特征交换
      |                                  |
      |<----- Pairing Response --------  |
      |                                  |
      |       生成TK=0 (Just Works)      | Phase 2: 认证
      |                                  |
      |       生成Mrand, 计算Mconfirm    |
      |                                  |
      |------ Pairing Confirm -------->  |
      |                                  |
      |       生成Srand, 计算Sconfirm    |
      |                                  |
      |<----- Pairing Confirm ---------  |
      |                                  |
      |------ Pairing Random --------->  | 发送Mrand
      |                                  |
      |       验证Mconfirm = c1(TK, Mrand, ...)|
      |                                  |
      |<----- Pairing Random ----------  | 发送Srand
      |                                  |
      | 验证Sconfirm = c1(TK, Srand, ...) |
      |                                  |
      |       生成STK = s1(TK, Srand, Mrand)   |
      |                                  |
      |------ Start Encryption -------->  | Phase 3: 加密
      |                                  |
      |<----- Encryption Change --------  |
      |                                  |
      |------ Encryption Info --------->  | Phase 4: 密钥分发
      |------ Master Identification --->  | (LTK, EDIV, Rand)
      |------ Identity Info ----------->  | (IRK)
      |------ Identity Address Info --->  | (Identity Address)
      |------ Signing Info ------------>  | (CSRK)
      |                                  |
      |<----- Identity Info -----------  |
      |<----- Identity Address Info ---  |
      |<----- Signing Info ------------  |
      |                                  |
      配对完成

12.2 配对方法 (4种)

配对方法枚举:

c 复制代码
typedef enum {
    PAIRING_METH_JUST_WORKS     = 0,  // Just Works (无需用户交互)
    PAIRING_METH_PASSKEY_ENTRY  = 1,  // Passkey Entry (6位数字)
    PAIRING_METH_OOB            = 2,  // Out of Band (带外数据)
    PAIRING_METH_NUMERIC_COMP   = 3,  // Numeric Comparison (数字比较, SC only)
} smp_pairing_method_t;

IO能力与配对方法映射表:

复制代码
IO能力定义 (bt_common_define.h:1394-1397):
#define BTM_IO_DISPLAY_ONLY   0  // 仅显示
#define BTM_IO_DISPLAY_YESNO  1  // 显示+Yes/No
#define BTM_IO_KEYBOARD_ONLY  2  // 仅键盘
#define BTM_IO_NO_IO          3  // 无IO

Legacy Pairing方法选择:
                    | Display | Display | Keyboard | No IO
                    | Only    | Yes/No  | Only     |
--------------------+---------+---------+----------+-------
Display Only        | JW      | JW      | PE(I)    | JW
Display Yes/No      | JW      | JW      | PE(I)    | JW
Keyboard Only       | PE(R)   | PE(R)   | PE(Both) | JW
No IO               | JW      | JW      | JW       | JW
OOB Available       | OOB     | OOB     | OOB      | OOB

Secure Connections方法选择:
                    | Display | Display | Keyboard | No IO
                    | Only    | Yes/No  | Only     |
--------------------+---------+---------+----------+-------
Display Only        | JW      | NC      | PE(I)    | JW
Display Yes/No      | NC      | NC      | PE(I)    | JW
Keyboard Only       | PE(R)   | PE(R)   | PE(Both) | JW
No IO               | JW      | JW      | JW       | JW
OOB Available       | OOB     | OOB     | OOB      | OOB

JW: Just Works
PE: Passkey Entry (I=Initiator输入, R=Responder输入, Both=双向)
NC: Numeric Comparison (数字比较)

12.3 LE Legacy Pairing vs LE Secure Connections

Legacy Pairing特点:

c 复制代码
// 使用STK (Short Term Key) 作为临时密钥
// 密钥长度: 128 bits
// 加密算法: AES-128-CCM
// 弱点: 易受MITM攻击 (被动窃听)

// Legacy配对密钥生成:
// 1. TK (Temporary Key): 根据配对方法生成
//    - Just Works: TK = 0
//    - Passkey Entry: TK = 6位数字 (000000-999999)
//    - OOB: TK = 128-bit random number
//
// 2. Confirm值计算:
//    Mconfirm = c1(TK, Mrand, Pairing Req, Pairing Rsp, Initiating Device, Responding Device)
//    Sconfirm = c1(TK, Srand, ...)
//
// 3. STK生成:
//    STK = s1(TK, Srand, Mrand)
//
// 4. LTK生成: 在加密链路上随机生成

Secure Connections特点:

c 复制代码
// 使用ECDH (Elliptic Curve Diffie-Hellman) 公钥密码
// 密钥长度: 256 bits (P-256 curve)
// 抗MITM: 提供主动攻击防护
// 支持Numeric Comparison方法

// SC配对密钥生成:
// 1. 生成P-256公私钥对:
//    Local: PKa (public), SKa (private)
//    Peer:  PKb (public), SKb (private)
//
// 2. 计算DHKey:
//    DHKey = P256(SKa, PKb) = P256(SKb, PKa)
//
// 3. 生成Nonce: Na, Nb (128-bit random)
//
// 4. 计算Confirm值 (Numeric Comparison):
//    Va = g2(PKax, PKbx, Na, Nb)  // 6位数字
//    双方显示Va进行比较
//
// 5. 计算Check值:
//    Ea = f5(DHKey, Na, Nb, ...) -> MacKey, LTK
//    Ca = f6(MacKey, Na, Nb, ...)
//
// 6. 验证Check:
//    接收对方的Cb, 验证匹配

加密函数 (gap_i.h:166-192):

c 复制代码
// Legacy Pairing函数
bool smp_e(const uint8_t *key_128_le, const uint8_t *plain_128_le,
           gap_key_callback_t cmpl, void *priv);  // AES-128加密

// Secure Connections函数
bool smp_f5_gen_key_T(const uint8_t *DHKey_256_le,
                      gap_key_callback_t func, void *priv);  // 生成T
bool smp_f5_gen_mackey_ltk(const uint8_t *key_T_128_le, ...); // 生成MacKey和LTK
bool smp_f6(const uint8_t *W_128_le, ...);                     // 生成Check值
bool smp_g2(const uint8_t *PKax_U_256_le, ...);                // 生成6位数字
bool smp_h6(const uint8_t *W_128_le, ...);                     // BR/EDR密钥派生
bool smp_h7(const uint8_t *salt_128_le, ...);                  // BR/EDR密钥派生

12.4 密钥分发 (LTK/IRK/CSRK/EDIV/RAND)

密钥类型:

c 复制代码
// SMP密钥分发Opcode (gap_i.h:219-223)
SMP_ENCRYPTION_INFO         = 0x06,  // LTK (Long Term Key)
SMP_CENTRAL_IDENTIFICATION  = 0x07,  // EDIV + Rand (Legacy only)
SMP_IDENTITY_INFO           = 0x08,  // IRK (Identity Resolving Key)
SMP_IDENTITY_ADDR_INFO      = 0x09,  // Identity Address
SMP_SIGNING_INFO            = 0x0a,  // CSRK (Connection Signature Resolving Key)

密钥用途:

复制代码
1. LTK (Long Term Key) - 128/256 bits
   用途: 链路层加密
   分发: Phase 3密钥分发阶段
   存储: 用于重连时快速加密

   Legacy: 需要EDIV + Rand标识
   SC: LTK直接由f5生成,无需EDIV/Rand

2. EDIV (Encrypted Diversifier) - 16 bits
   RAND (Random Number) - 64 bits
   用途: 标识Legacy Pairing的LTK
   流程: 重连时,Slave发送LTK Request(EDIV, Rand)
         Master根据EDIV+Rand查找对应的LTK

3. IRK (Identity Resolving Key) - 128 bits
   用途: 解析RPA (Resolvable Private Address)
   算法: hash = ah(IRK, prand[23:0])
         if (hash == rpa[47:24]) -> 地址匹配

   隐私保护: 设备使用RPA后,仅持有IRK的设备能识别

4. CSRK (Connection Signature Resolving Key) - 128 bits
   用途: 数据签名 (无需加密连接)
   算法: Signature = AES-CMAC(CSRK, data)
   应用: 无连接数据完整性验证

5. Identity Address - 6 bytes + 1 byte type
   用途: 设备的真实身份地址 (Public or Static Random)
   作用: 与IRK配对使用,用于地址解析后的设备标识

密钥分发流程:

c 复制代码
// Initiator Key Distribution (gap_i.h:329-331)
uint8_t init_key_dist;  // Bit mask of keys to distribute
#define KEY_DIST_ENC_KEY    0x01  // LTK (+ EDIV/Rand for Legacy)
#define KEY_DIST_ID_KEY     0x02  // IRK + Identity Address
#define KEY_DIST_SIGN_KEY   0x04  // CSRK
#define KEY_DIST_LINK_KEY   0x08  // Link Key (BR/EDR CTKD)

// Responder Key Distribution
uint8_t resp_key_dist;  // Bit mask of keys to distribute

// 示例: 双向分发所有密钥
init_key_dist = 0x07;  // LTK + IRK + CSRK
resp_key_dist = 0x07;  // LTK + IRK + CSRK

12.5 CTKD跨传输密钥派生

CTKD (Cross-Transport Key Derivation) 允许BR/EDR和LE共享安全密钥:

CTKD函数 (gap_i.h:125-128, 186-189):

c 复制代码
// 通知LTK从Link Key派生
void gap_ctkd_notify_ltk_derived(gap_conn_item_t *bredr_conn,
                                  bt_addr_type_t peer_type,
                                  const bt_bdaddr_t *peer_addr,
                                  bool wait_peer_kdist);

// 通知Link Key从LTK派生
void gap_ctkd_notify_link_key_derived(gap_conn_item_t *conn,
                                       const bt_bdaddr_t *bt_addr,
                                       const uint8_t *link_key,
                                       bool wait_peer_ia);

// Link Key -> LTK派生
bool smp_linkkey_to_iltk(const uint8_t *linkkey, bool ct2,
                         gap_key_callback_t func, void *priv);
bool smp_iltk_to_ltk(const uint8_t *iltk,
                     gap_key_callback_t func, void *priv);

// LTK -> Link Key派生
bool smp_ltk_to_ilk(const uint8_t *ltk, bool ct2,
                    gap_key_callback_t func, void *priv);
bool smp_ilk_to_linkkey(const uint8_t *ilk,
                        gap_key_callback_t func, void *priv);

CTKD工作流程:

复制代码
场景1: BR/EDR已配对,LE首次连接
Step 1: BR/EDR已有Link Key
Step 2: LE连接时,使用h6/h7从Link Key派生LTK
        ilk = h6(Link_Key, "tmp1")
        ltk = h7(ilk, "lebr")
Step 3: 使用派生的LTK加密LE连接
Step 4: 交换IRK (可选)

场景2: LE已配对,BR/EDR首次连接
Step 1: LE已有LTK
Step 2: BR/EDR连接时,使用h6/h7从LTK派生Link Key
        iltk = h7(LTK, "brle")
        link_key = h6(iltk, "tmp2")
Step 3: 使用派生的Link Key进行BR/EDR配对
Step 4: 交换必要的密钥

优势:
- 避免重复配对
- 提升用户体验
- 维护统一的安全上下文

13. 错误码体系

13.1 HCI错误码 (bt_common_define.h:829-889)

c 复制代码
typedef uint8_t btif_error_code_t;

// 常见HCI错误码
#define BTIF_BEC_NO_ERROR             0x00  // 成功
#define BTIF_BEC_UNKNOWN_HCI_CMD      0x01  // 未知HCI命令
#define BTIF_BEC_NO_CONNECTION        0x02  // 无连接
#define BTIF_BEC_HARDWARE_FAILURE     0x03  // 硬件故障
#define BTIF_BEC_PAGE_TIMEOUT         0x04  // Page超时
#define BTIF_BEC_AUTHENTICATE_FAILURE 0x05  // 认证失败
#define BTIF_BEC_MISSING_KEY          0x06  // 密钥丢失
#define BTIF_BEC_MEMORY_FULL          0x07  // 内存满
#define BTIF_BEC_CONNECTION_TIMEOUT   0x08  // 连接超时
#define BTIF_BEC_MAX_CONNECTIONS      0x09  // 达到最大连接数
#define BTIF_BEC_MAX_SCO_CONNECTIONS  0x0a  // 达到最大SCO连接数
#define BTIF_BEC_ACL_ALREADY_EXISTS   0x0b  // ACL连接已存在
#define BTIF_BEC_COMMAND_DISALLOWED   0x0c  // 命令不允许
#define BTIF_BEC_LIMITED_RESOURCE     0x0d  // 资源受限
#define BTIF_BEC_SECURITY_ERROR       0x0e  // 安全错误
#define BTIF_BEC_PERSONAL_DEVICE      0x0f  // 个人设备拒绝
#define BTIF_BEC_HOST_TIMEOUT         0x10  // 主机超时
#define BTIF_BEC_UNSUPPORTED_FEATURE  0x11  // 不支持的特性
#define BTIF_BEC_INVALID_HCI_PARM     0x12  // 无效HCI参数
#define BTIF_BEC_USER_TERMINATED      0x13  // 用户终止 (常见断连原因)
#define BTIF_BEC_LOW_RESOURCES        0x14  // 资源不足
#define BTIF_BEC_POWER_OFF            0x15  // 关机
#define BTIF_BEC_LOCAL_TERMINATED     0x16  // 本地终止
#define BTIF_BEC_REPEATED_ATTEMPTS    0x17  // 重复尝试
#define BTIF_BEC_PAIRING_NOT_ALLOWED  0x18  // 不允许配对
#define BTIF_BEC_UNKNOWN_LMP_PDU      0x19  // 未知LMP PDU
#define BTIF_BEC_UNSUPPORTED_REMOTE   0x1a  // 远端不支持
#define BTIF_BEC_SCO_OFFSET_REJECT    0x1b  // SCO偏移拒绝
#define BTIF_BEC_SCO_INTERVAL_REJECT  0x1c  // SCO间隔拒绝
#define BTIF_BEC_SCO_AIR_MODE_REJECT  0x1d  // SCO空口模式拒绝
#define BTIF_BEC_INVALID_LMP_PARM     0x1e  // 无效LMP参数
#define BTIF_BEC_UNSPECIFIED_ERR      0x1f  // 未指定错误
#define BTIF_BEC_UNSUPPORTED_LMP_PARM 0x20  // 不支持的LMP参数
#define BTIF_BEC_ROLE_CHG_NOT_ALLOWED 0x21  // 不允许角色切换
#define BTIF_BEC_LMP_RESPONSE_TIMEOUT 0x22  // LMP响应超时
#define BTIF_BEC_LMP_TRANS_COLLISION  0x23  // LMP传输冲突
#define BTIF_BEC_LMP_PDU_NOT_ALLOWED  0x24  // LMP PDU不允许
#define BTIF_BEC_ENCRYP_MODE_NOT_ACC  0x25  // 加密模式不接受
#define BTIF_BEC_UNIT_KEY_USED        0x26  // Unit Key使用 (不安全)
#define BTIF_BEC_QOS_NOT_SUPPORTED    0x27  // QoS不支持
#define BTIF_BEC_INSTANT_PASSED       0x28  // Instant已过
#define BTIF_BEC_PAIR_UNITKEY_NO_SUPP 0x29  // 配对Unit Key不支持
#define BTIF_BEC_NOT_FOUND            0xf1  // 未找到
#define BTIF_BEC_REQUEST_CANCELLED    0xf2  // 请求取消

// SDP错误码
#define BTIF_BEC_INVALID_SDP_PDU      0xd1  // 无效SDP PDU
#define BTIF_BEC_SDP_DISCONNECT       0xd2  // SDP断连
#define BTIF_BEC_SDP_NO_RESOURCES     0xd3  // SDP资源不足
#define BTIF_BEC_SDP_INTERNAL_ERR     0xd4  // SDP内部错误
#define BTIF_BEC_STORE_LINK_KEY_ERR   0xe0  // 存储Link Key错误

// BES厂商错误码
#define BT_ECODE_DISCONNECT_ITSELF      0xba  // 主动断连
#define BT_ECODE_IBRT_SLAVE_CLEANUP     0xbb  // IBRT从设备清理
#define BT_ECODE_SDP_OPEN_TIMEOUT       0xbc  // SDP打开超时
#define BT_ECODE_SDP_ClIENT_TX_TIMEOUT  0xbd  // SDP客户端发送超时

#define BTIF_BEC_BT_LINK_REAL_DISCONNECTED 0xb8  // BT链路真正断连
#define BTIF_BEC_BT_CANCEL_PAGE       0xb9       // 取消Page

13.2 错误码分类与处理

按严重程度分类:

c 复制代码
// 1. 正常断连 (可忽略)
case BTIF_BEC_USER_TERMINATED:       // 0x13 - 用户主动断连
case BTIF_BEC_LOCAL_TERMINATED:      // 0x16 - 本地主动断连
case BTIF_BEC_POWER_OFF:             // 0x15 - 关机
    // 正常流程,无需告警

// 2. 超时类错误 (可能是信号问题)
case BTIF_BEC_PAGE_TIMEOUT:          // 0x04 - Page超时
case BTIF_BEC_CONNECTION_TIMEOUT:    // 0x08 - 连接超时
case BTIF_BEC_HOST_TIMEOUT:          // 0x10 - 主机超时
case BTIF_BEC_LMP_RESPONSE_TIMEOUT:  // 0x22 - LMP超时
    // 检查信号强度、距离、干扰

// 3. 安全类错误 (需要重新配对)
case BTIF_BEC_AUTHENTICATE_FAILURE:  // 0x05 - 认证失败
case BTIF_BEC_MISSING_KEY:           // 0x06 - 密钥丢失
case BTIF_BEC_SECURITY_ERROR:        // 0x0e - 安全错误
case BTIF_BEC_PAIRING_NOT_ALLOWED:   // 0x18 - 不允许配对
    // 清除配对记录,重新配对

// 4. 资源类错误 (系统问题)
case BTIF_BEC_MEMORY_FULL:           // 0x07 - 内存满
case BTIF_BEC_LIMITED_RESOURCE:      // 0x0d - 资源受限
case BTIF_BEC_LOW_RESOURCES:         // 0x14 - 资源不足
case BTIF_BEC_MAX_CONNECTIONS:       // 0x09 - 达到最大连接数
    // 释放资源,检查内存泄漏

// 5. 硬件类错误 (严重)
case BTIF_BEC_HARDWARE_FAILURE:      // 0x03 - 硬件故障
    // 重启设备,检查硬件

错误处理示例:

c 复制代码
void app_bt_handle_disconnect(uint8_t device_id, uint8_t error_code)
{
    LOG("Disconnect: device=%d reason=0x%02x", device_id, error_code);

    switch (error_code) {
        case BTIF_BEC_CONNECTION_TIMEOUT:
            // 连接超时: 可能是距离太远或信号干扰
            LOG("Connection timeout - check signal quality");
            // 可以尝试重连
            app_bt_retry_connection(device_id);
            break;

        case BTIF_BEC_AUTHENTICATE_FAILURE:
            // 认证失败: 清除配对信息
            LOG("Authentication failed - clear pairing");
            nv_record_delete_ble_pairing_info(device_id);
            break;

        case BTIF_BEC_USER_TERMINATED:
        case BTIF_BEC_LOCAL_TERMINATED:
            // 正常断连: 无需特殊处理
            LOG("Normal disconnection");
            break;

        default:
            // 其他错误: 记录日志
            LOG("Unexpected error: 0x%02x", error_code);
            break;
    }
}

14. LMP命令与扩展Opcode

14.1 LMP Opcode定义

LMP (Link Manager Protocol) 用于控制链路层行为:

基本LMP Opcode (bt_drv_interface.h:22-86):

c 复制代码
// LMP基础命令 (Opcode 1-66)
#define LMP_NAME_REQ_OPCODE                1   // 名称请求
#define LMP_NAME_RES_OPCODE                2   // 名称响应
#define LMP_ACCEPTED_OPCODE                3   // 接受
#define LMP_NOT_ACCEPTED_OPCODE            4   // 不接受
#define LMP_CLK_OFF_REQ_OPCODE             5   // 时钟偏移请求
#define LMP_CLK_OFF_RES_OPCODE             6   // 时钟偏移响应
#define LMP_DETACH_OPCODE                  7   // 分离
#define LMP_INRAND_OPCODE                  8   // 输入随机数
#define LMP_COMBKEY_OPCODE                 9   // 组合密钥
#define LMP_UNITKEY_OPCODE                10   // Unit密钥
#define LMP_AURAND_OPCODE                 11   // 认证随机数
#define LMP_SRES_OPCODE                   12   // 认证响应
#define LMP_TEMPRAND_OPCODE               13   // 临时随机数
#define LMP_TEMPKEY_OPCODE                14   // 临时密钥
#define LMP_ENC_MODE_REQ_OPCODE           15   // 加密模式请求
#define LMP_ENC_KEY_SIZE_REQ_OPCODE       16   // 加密密钥大小请求
#define LMP_START_ENC_REQ_OPCODE          17   // 开始加密请求
#define LMP_STOP_ENC_REQ_OPCODE           18   // 停止加密请求
#define LMP_SWITCH_REQ_OPCODE             19   // 主从切换请求
#define LMP_HOLD_OPCODE                   20   // Hold模式
#define LMP_HOLD_REQ_OPCODE               21   // Hold请求
#define LMP_SNIFF_REQ_OPCODE              23   // Sniff请求
#define LMP_UNSNIFF_REQ_OPCODE            24   // 退出Sniff
#define LMP_PARK_REQ_OPCODE               25   // Park请求
#define LMP_INCR_PWR_REQ_OPCODE           31   // 增加功率请求
#define LMP_DECR_PWR_REQ_OPCODE           32   // 降低功率请求
#define LMP_MAX_PWR_OPCODE                33   // 最大功率
#define LMP_MIN_PWR_OPCODE                34   // 最小功率
#define LMP_AUTO_RATE_OPCODE              35   // 自动速率
#define LMP_PREF_RATE_OPCODE              36   // 首选速率
#define LMP_VER_REQ_OPCODE                37   // 版本请求
#define LMP_VER_RES_OPCODE                38   // 版本响应
#define LMP_FEATS_REQ_OPCODE              39   // 特性请求
#define LMP_FEATS_RES_OPCODE              40   // 特性响应
#define LMP_QOS_OPCODE                    41   // QoS
#define LMP_QOS_REQ_OPCODE                42   // QoS请求
#define LMP_SCO_LINK_REQ_OPCODE           43   // SCO链路请求
#define LMP_RMV_SCO_LINK_REQ_OPCODE       44   // 移除SCO链路请求
#define LMP_MAX_SLOT_OPCODE               45   // 最大Slot
#define LMP_MAX_SLOT_REQ_OPCODE           46   // 最大Slot请求
#define LMP_TIMING_ACCU_REQ_OPCODE        47   // 时序精度请求
#define LMP_TIMING_ACCU_RES_OPCODE        48   // 时序精度响应
#define LMP_SETUP_CMP_OPCODE              49   // 设置完成
#define LMP_HOST_CON_REQ_OPCODE           51   // 主机连接请求
#define LMP_SLOT_OFF_OPCODE               52   // Slot偏移
#define LMP_SUPV_TO_OPCODE                55   // 监督超时
#define LMP_TEST_ACTIVATE_OPCODE          56   // 测试激活
#define LMP_TEST_CTRL_OPCODE              57   // 测试控制
#define LMP_ENC_KEY_SIZE_MASK_REQ_OPCODE  58   // 加密密钥大小掩码请求
#define LMP_ENC_KEY_SIZE_MASK_RES_OPCODE  59   // 加密密钥大小掩码响应
#define LMP_SET_AFH_OPCODE                60   // 设置AFH (自适应跳频)
#define LMP_ENCAPS_HDR_OPCODE             61   // 封装头
#define LMP_ENCAPS_PAYL_OPCODE            62   // 封装载荷
#define LMP_SP_CFM_OPCODE                 63   // 简单配对Confirm
#define LMP_SP_NB_OPCODE                  64   // 简单配对Number
#define LMP_DHKEY_CHK_OPCODE              65   // DHKey Check
#define LMP_PAUSE_ENC_AES_REQ_OPCODE      66   // 暂停AES加密请求

LMP扩展Opcode (Escape 4) (bt_drv_interface.h:88-114):

c 复制代码
// 使用Escape 4 (Opcode 127, ExtOpcode 1-34)
#define LMP_ACCEPTED_EXT_EXTOPCODE         1   // 接受 (扩展)
#define LMP_NOT_ACCEPTED_EXT_EXTOPCODE     2   // 不接受 (扩展)
#define LMP_FEATS_REQ_EXT_EXTOPCODE        3   // 特性请求 (扩展)
#define LMP_FEATS_RES_EXT_EXTOPCODE        4   // 特性响应 (扩展)
#define LMP_CLK_ADJ_EXTOPCODE              5   // 时钟调整
#define LMP_CLK_ADJ_ACK_EXTOPCODE          6   // 时钟调整确认
#define LMP_CLK_ADJ_REQ_EXTOPCODE          7   // 时钟调整请求
#define LMP_PKT_TYPE_TBL_REQ_EXTOPCODE    11   // 数据包类型表请求
#define LMP_ESCO_LINK_REQ_EXTOPCODE       12   // eSCO链路请求
#define LMP_RMV_ESCO_LINK_REQ_EXTOPCODE   13   // 移除eSCO链路请求
#define LMP_CH_CLASS_REQ_EXTOPCODE        16   // 信道分类请求
#define LMP_CH_CLASS_EXTOPCODE            17   // 信道分类
#define LMP_SSR_REQ_EXTOPCODE             21   // Sniff Subrating请求
#define LMP_SSR_RES_EXTOPCODE             22   // Sniff Subrating响应
#define LMP_PAUSE_ENC_REQ_EXTOPCODE       23   // 暂停加密请求
#define LMP_RESUME_ENC_REQ_EXTOPCODE      24   // 恢复加密请求
#define LMP_IO_CAP_REQ_EXTOPCODE          25   // IO能力请求 (SSP)
#define LMP_IO_CAP_RES_EXTOPCODE          26   // IO能力响应 (SSP)
#define LMP_NUM_COMPARISON_FAIL_EXTOPCODE 27   // 数字比较失败
#define LMP_PASSKEY_FAIL_EXTOPCODE        28   // Passkey失败
#define LMP_OOB_FAIL_EXTOPCODE            29   // OOB失败
#define LMP_KEYPRESS_NOTIF_EXTOPCODE      30   // 按键通知
#define LMP_PWR_CTRL_REQ_EXTOPCODE        31   // 功率控制请求
#define LMP_PWR_CTRL_RES_EXTOPCODE        32   // 功率控制响应
#define LMP_PING_REQ_EXTOPCODE            33   // Ping请求
#define LMP_PING_RES_EXTOPCODE            34   // Ping响应

LMP命令使用场景:

复制代码
连接建立:
1. LMP_VER_REQ/RES - 交换版本信息
2. LMP_FEATS_REQ/RES - 交换特性支持
3. LMP_NAME_REQ/RES - 获取设备名称 (可选)
4. LMP_CLK_OFF_REQ/RES - 时钟偏移同步

配对认证 (Simple Secure Pairing):
1. LMP_IO_CAP_REQ/RES - 交换IO能力
2. LMP_SP_CFM - 简单配对Confirm (Passkey Entry)
3. LMP_SP_NB - 简单配对Number (Numeric Comparison)
4. LMP_DHKEY_CHK - DHKey Check (SC)

加密:
1. LMP_ENC_MODE_REQ - 请求加密模式
2. LMP_ENC_KEY_SIZE_REQ - 协商密钥大小
3. LMP_START_ENC_REQ - 开始加密
4. LMP_PAUSE_ENC_REQ - 暂停加密 (密钥刷新)
5. LMP_RESUME_ENC_REQ - 恢复加密

功率控制:
1. LMP_INCR_PWR_REQ - 请求增加功率
2. LMP_DECR_PWR_REQ - 请求降低功率
3. LMP_MAX_PWR - 使用最大功率
4. LMP_MIN_PWR - 使用最小功率

低功耗模式:
1. LMP_SNIFF_REQ - 进入Sniff模式
2. LMP_UNSNIFF_REQ - 退出Sniff模式
3. LMP_SSR_REQ/RES - Sniff Subrating (降低Sniff功耗)
4. LMP_HOLD_REQ - 进入Hold模式
5. LMP_PARK_REQ - 进入Park模式

链路质量:
1. LMP_SET_AFH - 设置自适应跳频
2. LMP_CH_CLASS_REQ - 信道分类请求
3. LMP_AUTO_RATE - 自动速率调整
4. LMP_MAX_SLOT_REQ - 协商最大Slot数

15. Slot时间片调度机制深度解析

15.1 BLE Connection Event Slot分配

BLE连接事件占用特定的时间片进行数据交换:

连接间隔与Slot关系:

复制代码
BLE连接间隔 = N × 1.25ms (N: 6-3200)
最小间隔: 7.5ms (N=6)
最大间隔: 4000ms (N=3200)

每个Connection Event:
|<------- Connection Interval -------->|
|   CE_0   |   CE_1   |   CE_2   | ...
|--1.25ms--|--1.25ms--|--1.25ms--|

Connection Event内部:
| AnchorPoint | Tx | Rx | Tx | Rx | ... |
|<----------- Connection Event -------->|
             最长持续时间受限于间隔

Connection Event Slot分配:
- 每个LL PDU传输占用一个Slot
- Slot长度取决于PDU大小和PHY速率
- Master先发送 (TX slot)
- Slave响应 (RX slot)
- 交替进行直到事件结束或无数据

BLE Slot时长计算:

c 复制代码
// 1M PHY:
// T_IFS (Inter Frame Space) = 150us
// Preamble = 8us (1 byte @ 1Mbps)
// Access Address = 32us (4 bytes)
// PDU Header = 16us (2 bytes)
// Payload = N × 8us
// CRC = 24us (3 bytes)
// Total = 8 + 32 + 16 + N×8 + 24 + 150 = 230 + N×8 (us)

// 最小Slot (空PDU): 230us
// 最大Slot (251字节): 230 + 251×8 = 2238us ≈ 2.24ms

// 2M PHY: 时间减半
// Coded PHY (S=8): 时间×8 (用于长距离)

15.2 TWS私有Slot调度优化

TWS (True Wireless Stereo) 场景下的特殊Slot调度:

TWS Slot优化策略:

c 复制代码
// TWS场景: 主耳+从耳+手机
// 需要在同一个Connection Interval内完成:
// 1. 手机 -> 主耳 (音频数据)
// 2. 主耳 -> 从耳 (音频数据+控制信令)
// 3. 从耳 -> 主耳 (状态反馈)

// 时序优化 (假设15ms连接间隔):
// |<-------- 15ms Connection Interval -------->|
// | Phone->Master | Master->Slave | Slave->Master |
// |   5ms         |    5ms        |     5ms       |
//     CE0             CE1 (TWS私有)    CE2

// Slot对齐策略:
void bt_drv_reg_op_music_link_config(uint16_t active_link,
                                      uint8_t active_role,
                                      uint16_t inactive_link,
                                      uint8_t inactive_role);

// TWS Slot调度函数
uint32_t bt_drv_reg_op_get_multi_ibrt_slice(uint8_t active);

TWS时间片分配示例:

复制代码
标准A2DP场景 (非TWS):
Connection Interval = 15ms
|<----- 15ms ----->|<----- 15ms ----->|
| Phone -> Earbud | Phone -> Earbud |
|   数据传输      |   数据传输      |

TWS场景 (Enhanced IBRT):
|<---------- 15ms Connection Interval ---------->|
|  Phone   |   Master   |   Slave   |  Reserved  |
|  -> M    |   -> S     |   -> M    |            |
| 5ms 3slots| 5ms 3slots | 5ms 3slots|            |
  \          \            \
   \__音频    \__音频转发  \__状态同步
      下发

优化点:
1. Slot精确对齐: 避免冲突
2. 优先级管理: A2DP > BLE > SCO
3. Sniff协调: TWS链路同步进入Sniff
4. 延迟补偿: 主从耳音频同步

15.3 A2DP/SCO/BLE多链路Slot协调

多链路并发时的Slot仲裁机制:

Slot优先级定义:

c 复制代码
// BLE连接参数优先级 (app_ble.c:315-334)
enum {
    PRIORITY_NORMAL = 0,           // 默认/空闲
    PRIORITY_ABOVE_NORMAL0,        // A2DP
    PRIORITY_ABOVE_NORMAL1,        // AI流
    PRIORITY_ABOVE_NORMAL2,        // HFP/服务发现
    PRIORITY_HIGH,                 // OTA
};

// Slot仲裁优先级 (由低到高):
// 1. BLE Connection (可延迟)
// 2. BLE Advertising (可跳过)
// 3. A2DP Streaming (需要稳定)
// 4. SCO Voice (最高优先级,实时)

多链路Slot分配策略:

复制代码
场景1: A2DP + BLE同时活跃
A2DP Slot: 每15ms一次 (retransmission window)
BLE Slot:  每45ms一次 (可调整)

时间轴:
|<-15ms->|<-15ms->|<-15ms->|<-15ms->|
| A2DP   |BLE+A2DP| A2DP   |BLE+A2DP|
  3 slots  1+2slots 3 slots  1+2slots

场景2: SCO + A2DP + BLE
SCO Slot:  每7.5ms一次 (HV3: 3 slots)
A2DP Slot: 每15ms一次 (降低为2 slots)
BLE Slot:  每60ms一次 (降低频率)

时间轴:
|<-7.5ms->|<-7.5ms->|<-7.5ms->|<-7.5ms->|
| SCO     | SCO+A2DP| SCO     | SCO+BLE |
  3 slots   2+1 slot  3 slots   2+1 slot

冲突解决:
1. SCO优先: 强制占用Slot
2. A2DP降级: 减少packet size或retransmission
3. BLE延迟: 增加connection interval
4. 动态调整: 根据实时负载

Slot冲突检测与协调:

c 复制代码
// 检查Slot冲突
void bt_drv_reg_op_cs_monitor(void);

// Slot触发器设置
void bt_syn_set_tg_ticks(uint32_t val, uint16_t conhdl,
                         uint8_t mode, uint8_t trig_route,
                         bool no_link_trig);

// 取消Slot触发
void bt_syn_cancel_tg_ticks(uint8_t trig_route);

// Slot触发模式
#define ACL_TRIGGLE_MODE       1  // ACL连接触发
#define SCO_TRIGGLE_MODE       2  // SCO连接触发
15.3.1 SCO与BLE物理层时间片冲突深度分析

问题背景: SCO (Synchronous Connection-Oriented) 是蓝牙BR/EDR用于实时语音传输的链路,具有最高的时间片优先级。当SCO与BLE同时激活时,在物理层(RF射频层)会产生时间片竞争冲突。

物理层时间片竞争:

复制代码
物理层资源冲突示意图:

单个蓝牙控制器(BES芯片)只有一个射频收发器
├─ BR/EDR (Classic Bluetooth)
│   ├─ ACL (异步数据链路)
│   └─ SCO/eSCO (同步语音链路) ← 最高优先级
│
└─ BLE (Low Energy)
    ├─ Advertising (广播)
    ├─ Scanning (扫描)
    └─ Connection (连接)

时间轴上的Slot竞争:
|<---- BT_CLK = 312.5us ---->|<---- BT_CLK = 312.5us ---->|
|      SCO Slot (reserved)   |   BLE Connection Event     |
        ↑                            ↑
        强制占用                     可能被打断或延迟

SCO周期性占用:
HV3:  每7.5ms占用3个Slot (1.875ms)
EV3:  每7.5ms占用3个Slot (1.875ms)
mSBC: 每7.5ms占用3个Slot (eSCO窗口)

BLE连接事件:
Connection Interval: 可配置 (7.5ms - 4000ms)
Connection Event长度: 取决于数据量 (最长可达Connection Interval)

时间片冲突类型:

c 复制代码
// 类型1: SCO Slot完全覆盖BLE Connection Event
// 现象: BLE连接事件被跳过,导致supervision timeout或丢包

时间轴:
|<------- 7.5ms ------->|<------- 7.5ms ------->|
| SCO | ... | SCO | ... | SCO | ... | SCO | ... |
        ^BLE CE(被打断)            ^BLE CE(被跳过)

// 类型2: BLE连接间隔与SCO周期不同步
// 现象: 周期性地发生冲突,导致音质抖动或BLE延迟增加

SCO周期:    |----7.5ms----|----7.5ms----|----7.5ms----|
BLE间隔:    |------15ms------|------15ms------|
冲突点:         X                  X               X
            (每次都碰撞)       (每次都碰撞)    (持续碰撞)

// 类型3: 多链路并发场景
// SCO + A2DP + BLE同时活跃

时间轴 (最坏情况):
|<----- 7.5ms ----->|<----- 7.5ms ----->|
| SCO | A2DP | BLE | SCO | A2DP | BLE |
  3slot 2slot  ?     3slot 2slot  ?
                ^                  ^
              BLE被挤压          BLE被延迟

系统应对策略:

策略1: BLE连接参数自适应调整 (app_ble.c:1024-1039):

c 复制代码
// 检测SCO状态并动态调整BLE连接间隔
static void fp_update_ble_connect_param_timer_handler(void const *param)
{
    if (delay_update_conidx != GAP_INVALID_CONIDX) {
        // 关键判断: 检测SCO是否激活
        if (amgr_is_bluetooth_sco_on()) {
            // ✅ SCO激活 -> 强制切换到HFP_ON模式
            // HFP_ON: 60ms连接间隔 (48 × 1.25ms)
            // 目的: 减少BLE占用时间片的频率,为SCO让路
            app_ble_update_conn_param_mode_of_specific_connection(
                delay_update_conidx, BLE_CONN_PARAM_MODE_HFP_ON, true);
        } else {
            // ❌ SCO未激活 -> 恢复到默认模式
            // DEFAULT: 45ms连接间隔 (36 × 1.25ms)
            app_ble_update_conn_param_mode_of_specific_connection(
                delay_update_conidx, BLE_CONN_PARAM_MODE_DEFAULT, true);
        }
        delay_update_conidx = GAP_INVALID_CONIDX;
    }
}

// 连接参数对比:
// DEFAULT模式: 45ms间隔 -> 每秒请求22次BLE CE
// HFP_ON模式:  60ms间隔 -> 每秒请求16次BLE CE
// 降低频率:    减少27% -> 更多时间片留给SCO

策略2: TWS Poll间隔在SCO场景下的动态调整 (bt_drv_reg_op.cpp:1514-1522):

c 复制代码
// TWS私有链路在SCO场景下的Slot调整
void btdrv_reg_op_set_private_tws_poll_interval(
    uint16_t poll_interval,         // 正常场景下的poll间隔
    uint16_t poll_interval_in_sco)  // SCO场景下的poll间隔
{
    // poll_interval必须是4的倍数
    ASSERT_ERR((poll_interval % 4 == 0));

    // 在SCO激活时,TWS链路会自动切换到poll_interval_in_sco
    // 目的: 降低主从耳之间的同步频率,减少与SCO的冲突

    // 示例配置:
    // 正常模式: poll_interval = 20ms (32 slots)
    // SCO模式:  poll_interval_in_sco = 40ms (64 slots)
    // 效果:     TWS同步频率降低50%,为SCO腾出更多Slot
}

策略3: 物理层Slot仲裁优先级 (硬件控制器层):

c 复制代码
// BES蓝牙控制器的Slot仲裁优先级(固定):
// Priority Level (由高到低):
//
// 1. SCO/eSCO (实时语音)
//    - 周期性强制占用,不可被打断
//    - HV3: 每7.5ms占用3个Slot
//    - Latency: 0 (零延迟)
//
// 2. ACL Sniff Anchor Point (ACL同步点)
//    - Sniff模式下的必须监听点
//    - 丢失会导致连接超时
//
// 3. BLE Connection Event (BLE连接事件)
//    - 可以被SCO打断
//    - 可以延迟到下一个Connection Interval
//    - Supervision Timeout保护: 2秒
//
// 4. ACL Active Mode (ACL活跃传输)
//    - A2DP音频流传输
//    - 可以降低packet type (DH5->DH3->DM3)
//
// 5. BLE Advertising (BLE广播)
//    - 优先级最低
//    - 可以跳过广播事件
//
// 硬件实现:
// - Slot Arbiter硬件模块自动处理冲突
// - SCO Slot预留: 在SCO建立时预留固定时间片
// - BLE CE延迟: 如果检测到冲突,自动推迟到下一个窗口

策略4: 15ms最小间隔保护机制 (app_ble.c:1094-1099):

c 复制代码
// 防止BLE连接间隔过短导致频繁冲突
static void app_ble_conn_param_update_req(gap_conn_update_req_t *update_req)
{
    uint16_t conn_interval_min_1_25ms = update_req->params_req.conn_interval_min_1_25ms;
    uint32_t conn_interval_min_us = conn_interval_min_1_25ms * 1250;

    // ⚠️ 如果BLE连接间隔 < 15ms
    // 问题: BLE每15ms就会请求时间片,与SCO (7.5ms周期) 产生频繁碰撞
    //
    // SCO周期:     |--7.5ms--|--7.5ms--|--7.5ms--|
    // BLE (10ms):  |----10ms----|----10ms----|
    // 冲突点:          X            X
    //              (每次都撞)   (每次都撞)
    //
    // 如果允许< 15ms间隔:
    // - BLE占用过于频繁,SCO语音可能出现卡顿
    // - 控制器Slot仲裁压力增大
    // - 系统功耗上升

    if (conn_interval_min_us < 15000) {
        // 拒绝过短的间隔,延迟10秒后重新评估
        fp_update_ble_connect_param_start(gap_zero_based_conidx(update_req->con_idx));
        accept = true; // 暂时接受,但稍后会强制调整
    }

    gap_update_le_conn_parameters_rsp(update_req->con_idx,
                                        &update_req->params_req,
                                        accept);
}

// 15ms的选择原因:
// - SCO周期: 7.5ms (HV3/EV3)
// - 15ms = 2 × SCO周期
// - BLE每隔2个SCO周期请求一次时间片,避免每次都冲突

实际场景时序分析:

场景: 通话中 + BLE连接 + A2DP暂停

复制代码
时间轴 (以Slot为单位, 1 Slot = 0.625ms):

|<------------- 7.5ms (12 slots) ------------>|<------------- 7.5ms (12 slots) ------------>|
| SCO  | SCO  | SCO  | ... | ... | BLE  | ... | SCO  | SCO  | SCO  | ... | ... | BLE  | ... |
  TX/RX  TX/RX  TX/RX              CE                TX/RX  TX/RX  TX/RX              CE

  0-1.875ms:        SCO强制占用 (3 slots)
  1.875-7.5ms:      空闲/其他链路
  5-6ms:            BLE Connection Event (如果没有与SCO冲突)
  7.5-9.375ms:      下一个SCO周期开始

BLE Connection Interval = 60ms (HFP_ON模式)
每60ms只请求一次BLE CE,大部分时间片留给SCO

对比: 如果BLE Interval = 10ms
|<-- 10ms -->|<-- 10ms -->|<-- 10ms -->|
  每10ms请求一次,几乎每次都与SCO碰撞
  SCO:     X      X      X      X      X
           碰撞   碰撞   碰撞   碰撞   碰撞

日志分析示例 (R_COM4_time_data@01-20_15-49-45.log):

复制代码
# 场景1: 正常BLE连接 (无SCO)
[18:30:45.123] [BLE] Connection interval: 36 (45ms) - DEFAULT模式
[18:30:45.168] [BLE] Connection Event: CE_0, latency=0ms
[18:30:45.213] [BLE] Connection Event: CE_1, latency=0ms

# 场景2: 来电,SCO建立
[18:31:20.456] [SCO] SCO connection setup: codec=mSBC, interval=7.5ms
[18:31:20.458] [BLE] Detect SCO active, update conn param to HFP_ON
[18:31:20.460] [BLE] Update interval: 48 (60ms)  ← 自动延长间隔
[18:31:20.520] [BLE] Connection Event: CE_5, latency=2ms  ← 被SCO延迟了2ms
[18:31:20.580] [BLE] Connection Event: CE_6, latency=0ms

# 场景3: 通话结束,SCO断开
[18:32:50.789] [SCO] SCO disconnected
[18:32:50.800] [BLE] Restore conn param to DEFAULT
[18:32:50.802] [BLE] Update interval: 36 (45ms)  ← 恢复到默认间隔

性能指标对比:

场景 BLE间隔 SCO状态 BLE丢包率 SCO音质 系统负载
仅BLE 45ms 0% N/A
BLE+SCO (无优化) 45ms 7.5ms周期 5-10% 偶尔卡顿
BLE+SCO (优化后) 60ms 7.5ms周期 <1% 稳定
BLE+SCO (激进) 15ms 7.5ms周期 15-20% 严重卡顿 很高

小结:

  1. 根本原因: 单射频控制器时间片竞争,SCO具有最高优先级
  2. 核心策略: 检测SCO状态,自动延长BLE连接间隔(45ms→60ms)
  3. 协同优化: TWS Poll间隔同步调整,减少主从耳同步对SCO的影响
  4. 保护机制: 拒绝<15ms的BLE间隔请求,避免频繁冲突
  5. 硬件支持: Slot Arbiter自动仲裁,SCO预留时间片

15.4 Sniff模式的Slot管理

Sniff模式通过减少活跃Slot降低功耗:

Sniff参数:

c 复制代码
typedef struct {
    uint16_t sniff_max_interval;  // 最大Sniff间隔 (slots, 0.625ms)
    uint16_t sniff_min_interval;  // 最小Sniff间隔
    uint16_t sniff_attempt;       // Sniff尝试次数
    uint16_t sniff_timeout;       // Sniff超时 (slots)
} sniff_params_t;

// 示例: 轻度Sniff (音乐播放)
// Interval: 800 slots (500ms)
// Attempt:  4 slots (2.5ms)
// Timeout:  1 slots (0.625ms)

// 示例: 深度Sniff (空闲状态)
// Interval: 2000 slots (1.25s)
// Attempt:  2 slots (1.25ms)
// Timeout:  1 slots (0.625ms)

Sniff Slot时序:

复制代码
Normal模式 (Active所有Slot):
|-----|-----|-----|-----|-----|-----|-----|-----|
| TX  | RX  | TX  | RX  | TX  | RX  | TX  | RX  |
  连续活跃,功耗高

Sniff模式 (周期性唤醒):
|<------- Sniff Interval = 500ms -------->|
|-----|                               |-----|
| TX/RX|                              | TX/RX|
  Attempt                              Attempt
  2.5ms                                2.5ms

Sniff Subrating (SSR) - 进一步优化:
|<- Sniff Int ->|<- Sniff Int ->|<- Sniff Int ->|
|-----|         |               |-----|         |
| TX/RX|        |               | TX/RX|        |
  实际监听        跳过(无数据)     实际监听

功耗对比:
Active:    100% duty cycle
Sniff:     0.5% duty cycle (500ms间隔,2.5ms attempt)
Sniff+SSR: 0.25% duty cycle (每两个interval监听一次)

Sniff Subrating (SSR):

c 复制代码
// LMP SSR协商 (bt_drv_interface.h:101-102)
#define LMP_SSR_REQ_EXTOPCODE             21  // SSR请求
#define LMP_SSR_RES_EXTOPCODE             22  // SSR响应

// SSR工作原理:
// 1. 在Sniff基础上进一步降低监听频率
// 2. Subrate: 每N个Sniff Interval监听一次
// 3. Latency: 允许的最大延迟 (用于数据传输)

// 示例: Subrate = 3
// Sniff Interval = 500ms
// 实际监听周期 = 500ms × 3 = 1.5s

// 适用场景:
// - 长时间空闲 (无按键、无音频)
// - 仅保持连接 (心跳)
// - 快速恢复: 检测到数据后立即退出SSR

16. 总结

本文档详细介绍了BLE低功耗蓝牙的完整技术实现,包括:

  1. 协议基础: BLE协议栈层次、角色定义、地址类型
  2. 广播机制: 快慢广播切换、低功耗优化策略
  3. 连接管理: 连接建立流程、参数动态调整
  4. 数据传输: GATT服务架构、MTU交换、双向数据传输
  5. 状态管理: 完整的状态机设计和转换逻辑
  6. 代码实现: 详细的代码分析和实现细节
  7. 协议时序: HCI层面的完整时序分析
  8. 硬件RF层: RF配置、功率控制、时钟机制
  9. 物理层: Packet类型、AFH自适应跳频
  10. SMP安全: 26状态机、4种配对方法、密钥分发、CTKD
  11. 错误码: 完整的HCI错误码体系与处理策略
  12. LMP命令: 基本和扩展Opcode详解
  13. Slot调度: BLE/TWS/多链路/Sniff模式时间片管理

通过本文档,开发者可以:

  • 理解BLE的工作原理和协议栈结构
  • 掌握广播、连接、数据传输的完整流程
  • 深入了解底层RF、Slot调度、SMP安全机制
  • 学习低功耗优化和性能调优技巧
  • 快速定位和解决BLE相关问题
  • 掌握TWS和多链路并发的优化策略

建议新手按照文档顺序学习,从基础协议开始,逐步深入到底层实现和高级优化技巧。


附录

A. 术语表

术语 全称 说明
BLE Bluetooth Low Energy 低功耗蓝牙
GAP Generic Access Profile 通用访问配置文件
GATT Generic Attribute Profile 通用属性配置文件
ATT Attribute Protocol 属性协议
L2CAP Logical Link Control and Adaptation Protocol 逻辑链路控制和适配协议
HCI Host Controller Interface 主机控制器接口
MTU Maximum Transmission Unit 最大传输单元
CCCD Client Characteristic Configuration Descriptor 客户端特征配置描述符
UUID Universally Unique Identifier 通用唯一识别码
RPA Resolvable Private Address 可解析私有地址
IRK Identity Resolving Key 身份解析密钥
LTK Long Term Key 长期密钥
PHY Physical Layer 物理层

附录C. API快速参考

本章节提供了文档中新增的所有重要API的快速查找参考。

C.1 地址管理API

API 功能 文件位置
bes_ble_gap_set_local_irk() 设置本地IRK bthost/adapter/inc/ble/gap/bes_gap_api.h:961
bes_ble_gap_get_current_ble_addr() 获取本地Identity Address bthost/adapter/inc/ble/gap/bes_gap_api.h:1123
bes_ble_gap_get_local_rpa_addr() 获取本地RPA地址 bthost/adapter/inc/ble/gap/bes_gap_api.h:1138
bes_ble_gap_read_local_rpa_by_adv_hdl() 通过广播handle读取RPA bthost/adapter/inc/ble/gap/bes_gap_api.h:1146
bes_ble_gap_set_rpa_timeout() 设置RPA超时时间 bthost/adapter/inc/ble/gap/bes_gap_api.h:641
bes_ble_gap_set_rpa_list() 设置RPA解析列表 bthost/adapter/inc/ble/gap/bes_gap_api.h:629
bes_ble_gap_set_bonded_devs_rpa_list() 添加已配对设备到解析列表 bthost/adapter/inc/ble/gap/bes_gap_api.h:636

C.2 广播数据构建API

API 功能 文件位置
gap_dt_add_raw_data() 添加原始广播数据 bthost/adapter/inc/adapter_service/gap_service.h:3107
gap_dt_add_flags() 添加Flags字段 bthost/adapter/inc/adapter_service/gap_service.h
app_ble_dt_set_flags() 设置广播Flags bthost/service/ble_app_new/inc/app_ble.h:451
app_ble_dt_set_local_name() 设置本地名称 bthost/service/ble_app_new/inc/app_ble.h:452
gap_dt_add_service_uuid_16() 添加16-bit UUID bthost/adapter/inc/adapter_service/gap_service.h
gap_dt_add_service_uuid_128() 添加128-bit UUID bthost/adapter/inc/adapter_service/gap_service.h

C.3 广播控制API

API 功能 文件位置
bes_ble_gap_start_adv() 启动所有已启用的广播 bthost/adapter/inc/ble/gap/bes_gap_api.h:606
bes_ble_gap_start_connectable_adv() 启动可连接广播 bthost/adapter/inc/ble/gap/bes_gap_api.h:599
bes_ble_gap_stop_adv_all() 停止所有广播 bthost/adapter/inc/ble/gap/bes_gap_api.h:580
bes_ble_gap_custom_adv_stop() 停止指定广播 bthost/adapter/inc/ble/gap/bes_gap_api.h:688
bes_ble_gap_force_switch_adv() 强制切换广播状态 bthost/adapter/inc/ble/gap/bes_gap_api.h:572
bes_ble_gap_refresh_adv_state() 刷新广播状态 bthost/adapter/inc/ble/gap/bes_gap_api.h:803
bes_ble_gap_is_in_advertising_state() 检查广播状态 bthost/adapter/inc/ble/gap/bes_gap_api.h:796
app_ble_refresh_adv_state_generic() 应用层刷新广播 bthost/service/ble_app_new/inc/app_ble.h:470

C.4 广播参数设置API

API 功能 文件位置
bes_ble_gap_param_set_adv_interval() 设置广播间隔 bthost/adapter/inc/ble/gap/bes_gap_api.h:780
bes_ble_set_all_adv_txpwr() 设置广播发射功率 bthost/adapter/inc/ble/gap/bes_gap_api.h:789
bes_ble_gap_set_adv_param() 设置广播参数结构 bthost/adapter/inc/ble/gap/bes_gap_api.h:651
bes_ble_gap_custom_adv_write_data() 写入自定义广播数据 bthost/adapter/inc/ble/gap/bes_gap_api.h:682
bes_ble_gap_custom_adv_start() 启动自定义广播 bthost/adapter/inc/ble/gap/bes_gap_api.h:667

C.5 白名单与过滤API

API 功能 文件位置
bes_ble_gap_set_white_list() 设置白名单 bthost/adapter/inc/ble/gap/bes_gap_api.h:612
bes_ble_gap_remove_white_list_user_item() 移除白名单 bthost/adapter/inc/ble/gap/bes_gap_api.h:621
bes_ble_gap_clear_white_list_for_mobile() 清除移动设备白名单 bthost/adapter/inc/ble/gap/bes_gap_api.h:869
app_ble_set_white_list() 应用层设置白名单 bthost/service/ble_app_new/inc/app_ble.h:435
app_ble_clear_white_list() 应用层清除白名单 bthost/service/ble_app_new/inc/app_ble.h:436

C.6 关键枚举类型

地址类型
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:211-233
BES_ADDR_PUBLIC              // 公共地址
BES_ADDR_RAND                // 随机地址
BES_ADDR_RPA_OR_PUBLIC       // RPA或公共地址
BES_ADDR_RPA_OR_RAND         // RPA或随机地址
BES_ADDR_NONE                // 匿名广播
广播通道
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:235-247
BES_ADV_CHNL_37_EN          // 通道37 (2402 MHz)
BES_ADV_CHNL_38_EN          // 通道38 (2426 MHz)
BES_ADV_CHNL_39_EN          // 通道39 (2480 MHz)
BES_ADV_ALL_CHNLS_EN        // 全部3个通道
广播Flags
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:188-207
BES_GAP_LE_LIM_DISCOVERABLE_FLG_BIT      // 限时可发现
BES_GAP_LE_GEN_DISCOVERABLE_FLG_BIT      // 通用可发现
BES_GAP_BR_EDR_NOT_SUPPORTED_BIT         // 不支持BR/EDR
BES_GAP_SIMUL_BR_EDR_LE_CONTROLLER_BIT   // 双模支持
广播过滤策略
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:249-261
BES_ADV_ALLOW_SCAN_ANY_CON_ANY           // 允许任何设备
BES_ADV_ALLOW_SCAN_WLST_CON_ANY          // 白名单扫描,任何连接
BES_ADV_ALLOW_SCAN_ANY_CON_WLST          // 任何扫描,白名单连接
BES_ADV_ALLOW_SCAN_WLST_CON_WLST         // 仅白名单设备
广播类型
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:263-276
BES_ADV_CONN_UNDIR          // 可连接非定向广播
BES_ADV_CONN_DIR            // 可连接高占空比定向广播
BES_ADV_DISC_UNDIR          // 可发现非定向广播
BES_ADV_NONCONN_UNDIR       // 不可连接非定向广播
BES_ADV_CONN_DIR_LDC        // 可连接低占空比定向广播

C.7 常用数据类型

地址结构
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:413-419
typedef struct bes_ble_bdaddr
{
    uint8_t addr[6];         // BD Address (LSB first)
    uint8_t addr_type;       // Address type
} bes_ble_bdaddr_t;
广播参数结构
c 复制代码
// bthost/adapter/inc/ble/gap/bes_gap_api.h:421-436
typedef struct
{
    BLE_ADV_ACTIVITY_USER_E actv_user;
    bool is_custom_adv_flags;
    BLE_ADV_ADDR_TYPE_E type;
    uint8_t *local_addr;
    bes_ble_bdaddr_t *peer_addr;
    uint32_t adv_interval;
    BLE_ADV_TYPE_E adv_type;
    ADV_MODE_E adv_mode;
    int8_t tx_power_dbm;
    uint8_t *adv_data;
    uint8_t adv_data_size;
    uint8_t *scan_rsp_data;
    uint8_t scan_rsp_data_size;
} bes_ble_gap_cus_adv_param_t;

C.8 文档新增章节索引

本次更新新增了以下章节:

章节 标题 页码/行号
1.3 BLE地址类型详解 行44-200
1.3.1 地址类型枚举定义 行55-89
1.3.2 Own Address Type 行91-111
1.3.3 地址相关API 行113-154
1.3.4 地址解析与隐私保护 行156-190
1.3.5 地址使用建议 行192-200
2.1.1 BLE广播通道与频率 行237-285
2.1.2 广播Flags设置 行287-341
2.1.3 广播数据构建API 行343-453
2.8 广播控制API 行887-1041
2.8.1 广播启动与停止 行891-938
2.8.2 广播刷新机制 行940-1005
2.8.3 广播参数设置 行1007-1041
2.9 白名单与过滤策略 行1043-1181
2.9.1 白名单API 行1047-1086
2.9.2 广播过滤策略 行1088-1148
2.9.3 扫描过滤策略 行1150-1171
2.9.4 白名单最佳实践 行1173-1181
2.10 连接发现性模式 行1182-1218
4.1.2 GATT over BR/EDR 行1623-1658

C.9 快速查找索引

按功能查找

功能 章节 关键API
设置地址类型 1.3 bes_ble_gap_set_local_irk()
构建广播数据 2.1.3 gap_dt_add_raw_data(), app_ble_dt_set_flags()
启动/停止广播 2.8.1 bes_ble_gap_start_adv(), bes_ble_gap_stop_adv_all()
刷新广播 2.8.2 bes_ble_gap_refresh_adv_state()
白名单管理 2.9 bes_ble_gap_set_white_list()
RPA管理 1.3.4 bes_ble_gap_set_rpa_list()
广播通道设置 2.1.1 BES_ADV_ALL_CHNLS_EN
GATT over BR/EDR 4.1.2 启用宏定义

B. 参考资料

  1. Bluetooth Core Specification v5.3
  2. Bluetooth SIG - Generic Access Profile
  3. Bluetooth SIG - Generic Attribute Profile
  4. HCI Reference Manual

文档版本 : v2.1
最后更新 : 2026-01-22
维护者: sanke

版本更新记录

v2.1 (2026-01-22)

  • 新增 8.8 CTKD跨传输密钥派生机制完整文档
    • CTKD定义、应用场景与价值
    • CTKD密钥派生原理(h4函数、AES-CMAC算法)
    • GAP_KDIST_LINKKEY密钥分发标志详解
    • CTKD代码实现示例(使能配置、SMP设置、iOS兼容处理)
    • CTKD密钥存储结构(gap_bond_sec_t、gap_conn_item_t)
    • CTKD与GATT over BR/EDR集成
    • CTKD完整时序图(BLE配对→密钥派生→BR/EDR连接)
    • CTKD实际操作例程(4个完整例程含日志分析)
    • CTKD常见问题排查与调试命令

v2.0 (2026-01-22)

  • ✅ 新增 1.3 BLE地址类型详解章节(Public, Random Static, RPA等)
  • ✅ 新增地址管理API文档(IRK设置、RPA获取、解析列表管理)
  • ✅ 新增 2.1.1 BLE广播通道与频率详细说明(37/38/39通道特性)
  • ✅ 新增 2.1.2 广播Flags设置文档
  • ✅ 新增 2.1.3 广播数据构建API(gap_dt_add_raw_data等)
  • ✅ 新增 2.8 广播控制API完整文档(启动/停止/刷新机制)
  • ✅ 新增 2.9 白名单与过滤策略详解
  • ✅ 新增 2.10 连接发现性模式说明
  • ✅ 新增 4.1.2 GATT over BR/EDR特性文档
  • ✅ 新增附录C API快速参考(包含所有新增API索引)
  • ✅ 补充完善了所有用户提到的缺失功能文档

v1.0 (初始版本)

  • 基础BLE技术文档框架
相关推荐
RisunJan4 小时前
Linux命令-last(查看用户登录历史)
linux·服务器·网络
咕噜企业分发小米4 小时前
腾讯云与火山引擎多云管理工具如何实现应用部署合规?
网络·腾讯云·火山引擎
2301_780789664 小时前
2025年UDP洪水攻击防护实战全解析:从T级流量清洗到AI智能防御
服务器·网络·人工智能·网络协议·安全·web安全·udp
不爱吃糖的程序媛4 小时前
OpenHarmony仓颉文档:全场景应用开发指南
运维·服务器
深耕AI5 小时前
【wordpress系列教程】07 网站迁移与备份
运维·服务器·前端·数据库
咕噜企业分发小米5 小时前
腾讯云多云管理工具如何与第三方合规工具集成以支持持续合规?
运维·服务器·游戏
这周也會开心5 小时前
云服务器部署项目
运维·服务器
min1811234565 小时前
软件升级全流程步骤详解
android·java·服务器
鱼香rose__5 小时前
Linux基础概念知识
linux·网络