杰理 SDK 文档中心
首页
首页
  • 概述

    • SDK 概览与产品定位
    • 支持芯片平台与蓝牙认证
    • SDK 架构与目录分层
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建系统
    • 板级工程与配置
    • 烧录与固件升级工具
  • 应用工程

    • 应用选择与工程总览
    • SPP + BLE 数传应用框架
    • 透传与 AT 指令示例
    • BLE 广播/中心与定位示例
    • 2.4G 私有协议与 Dongle 示例
    • 云平台接入示例
    • HID 人机交互应用框架
    • HID 示例工程(键盘/鼠标/遥控器/手柄)
    • Bluetooth Mesh 应用框架
    • Mesh 模型与 Mesh DFU 固件升级
    • Mesh 音频编解码演示
  • 芯片平台与硬件抽象

    • 芯片平台总览与差异
    • 音频编解码与时钟管理
    • 外设驱动接口(ADC/IIC/SPI/PWM/LED/充电)
    • 芯片配置工具与下载支持
  • 蓝牙协议栈

    • 蓝牙控制器层(btctrler)
    • 蓝牙协议栈与 Profile(btstack)
    • 蓝牙模块选择与配置
  • 媒体与音频框架

    • 音频流框架
    • 音频编解码与 A2DP 媒体
    • 音频效果处理(EQ/频谱/变调/环绕/超低音)
    • 本地 TWS 与音频同步
  • 系统服务与运行时

    • 实时操作系统与任务调度
    • 消息事件机制
    • 电源管理与低功耗
    • 存储与配置系统
    • 设备驱动框架(USB/RTC)
  • 应用公共组件

    • 音频应用组件
    • 设备外设抽象(按键/触摸/传感器/存储)
    • 蓝牙公共模块与消息联动
    • 调试与配置组件
    • 杰理关键词唤醒(jl_kws)
  • 第三方协议与云平台接入

    • 杰理 RCSP 私有协议
    • 低功耗蓝牙 Mesh 方案(llsync_mesh)
    • Sig Mesh 方案
    • 涂鸦协议接入
    • 腾讯连连接入
    • 华为 HiLink 接入
  • 固件升级与维护

    • OTA 升级机制
    • 升级补丁与版本维护
    • 升级工具链(BLE OTA / USB Dongle OTA)
  • 文档与开发资源

    • 数据手册与架构文档
    • 协议与云平台开发文档
    • 常见问题与技术支持

腾讯连连接入

本页介绍杰理 AC63 系列蓝牙 SDK 中接入腾讯云 IoT 小程序"腾讯连连"(Tencent LLSync / 腾讯连连低功耗蓝牙 LL 同步协议)的完整实现,包括应用入口、BLE GATT 服务、协议数据分发任务、设备信息/数据/OTA 三个消息通道以及绑定状态机。

Purpose and Scope

本页覆盖腾讯连连(LLSync)在 fw-AC63_BT_SDK 中的端到端接入能力:

  • apps/spp_and_le/examples/ll_sync/ 下的演示应用(app_ll_sync.c、ll_sync_demo.c、ll_sync_profile.h),即 CONFIG_APP_LL_SYNC 编译选项对应的工程;
  • apps/common/third_party_profile/Tecent_LL/ 下的腾讯官方 BLE IoT SDK 移植层(ll_task.c 数据分发任务、tecent_protocol/ 协议实现、include/ 头文件);
  • 设备信息(绑定/解绑/配网)、业务数据、OTA 三个消息通道的分发机制与绑定状态机。

以下内容不在本页范围,请参见对应页面:

  • BLE 协议栈基础(GATT/ATT/SM 配置)见蓝牙协议栈相关页面;
  • 通用 OTA 升级流程见 OTA 升级页面;
  • 其他第三方接入(如 Hilink)见各自集成页面。

Overview

腾讯连连(Tencent LianLian,简称 LL)是腾讯云 IoT 面向消费者的低功耗蓝牙配网与设备控制方案。设备端以 BLE GATT Server 形式对外提供服务,手机端"腾讯连连"小程序通过蓝牙扫描、连接设备,完成绑定(bind)、配网(Wi-Fi 信息下发)、业务数据收发与 OTA 升级。

本 SDK 的接入采用"透传 + 独立任务分发"架构:

  1. 设备作为 GATT Server,广播/响应携带腾讯自定义的 EIR Tag(0xd6 0x05 0x08 0x00 'J' 'L' 'A' 'I' 'S' 'D' 'K'),手机小程序据此识别设备;
  2. 手机向 GATT 写特征值时,写回调把原始数据写入环形缓冲 cbuf 并唤醒专用任务 tecent_ll_task;
  3. 任务按包头中的 packet_channel 字段将数据分发到设备信息通道(LL_DEVICE_INFO_MSG_CH)、业务数据通道(LL_DATA_MSG_CH)或 OTA 通道(LL_OTA_MSG_CH);
  4. 各通道处理函数(ble_device_info_msg_handle / ble_lldata_msg_handle / ble_ota_msg_handle)完成 LLSync 协议解析(绑定、时间同步、MTU 协商、数据加解密、OTA 分片),处理结果再经 GATT 通知(Notify/Indicate)回传手机。

该设计把"BLE 中断上下文"与"协议处理上下文"解耦:GATT 写回调只做入队,耗时协议解析全部放到独立任务中执行,避免阻塞蓝牙协议栈。

Architecture

flowchart TD
    subgraph sg_App["应用层 (apps/spp_and_le/examples/ll_sync)"]
        APP["app_ll_sync.c<br/>应用状态机 ACTION_LL_SYNC"]
        DEMO["ll_sync_demo.c<br/>GATT Server / 广播 / 连接参数"]
        PROFILE["ll_sync_profile.h<br/>特征值定义"]
    end

    subgraph sg_SDK["腾讯 LLSync SDK 移植层 (Tecent_LL)"]
        TASK["ll_task.c<br/>tecent_ll_task 分发任务 + cbuf"]
        DEV["tecent_protocol/ble_qiot_llsync_device.c<br/>设备信息通道"]
        DATA["tecent_protocol/ble_qiot_llsync_data.c<br/>业务数据通道"]
        OTA["tecent_protocol/ble_qiot_llsync_ota.c<br/>OTA 通道"]
        EVT["tecent_protocol/ble_qiot_llsync_event.c<br/>事件上报"]
        HDR["include/ble_qiot_llsync_*.h<br/>协议定义与导出接口"]
    end

    subgraph sg_BT["蓝牙协议栈"]
        STACK["btstack (GATT/ATT/SM)"]
    end

    APP -->|"llsync_app_start"| DEMO
    DEMO -->|"att_write_callback"| TASK
    TASK -->|"packet_channel 分发"| DEV
    TASK --> DATA
    TASK --> OTA
    DEV --> EVT
    DATA --> EVT
    OTA --> EVT
    DEMO -->|"GATT 服务注册"| STACK
    STACK -->|"BLE 事件/HCI 事件"| APP
    HDR -.->|"类型与常量"| TASK
    HDR -.->|"类型与常量"| DEV
    HDR -.->|"类型与常量"| DATA
    HDR -.->|"类型与常量"| OTA

架构说明:

  • 应用层负责生命周期:app_ll_sync.c 中的状态机在收到 ACTION_LL_SYNC 时启动 llsync_app_start(),初始化时钟与蓝牙协议栈;ll_sync_demo.c 注册 GATT Server(读/写/事件回调)、配置广播与连接参数。
  • SDK 移植层是腾讯 BLE IoT(ble_qiot)SDK 在本平台的落地:ll_task.c 提供任务化收包骨架;tecent_protocol/ 四个 .c 文件分别实现设备信息、业务数据、OTA、事件四类协议处理。
  • 数据流方向:手机小程序 → BLE 写请求 → GATT 写回调 → cbuf 环形缓冲 → tecent_ll_task → 按通道分发 → 协议处理 → 响应经 GATT 通知回手机。

以下源码链接基于 master 分支:https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/blob/master

工程结构与文件职责

腾讯连连接入涉及两个目录,职责边界清晰:

文件职责
apps/spp_and_le/examples/ll_sync/app_ll_sync.c应用入口:状态机、启动流程、软关机、电源事件、HCI 事件转发
apps/spp_and_le/examples/ll_sync/ll_sync_demo.cGATT Server 演示:MTU/缓存/广播/连接参数/SM 配置、读写与事件回调
apps/spp_and_le/examples/ll_sync/ll_sync_profile.h腾讯 LLSync 自定义 GATT Profile(特征值 UUID)定义
apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.c协议数据接收任务:信号量 + 环形缓冲 + 通道分发
apps/common/third_party_profile/Tecent_LL/tecent_ll_demo/ll_task.hLL_PACKET_CONTROL 控制块与包头定义
apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_device.c设备信息通道:绑定/解绑/配网/时间同步/MTU 协商
apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_data.c业务数据通道:LLSync 数据加解密收发
apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_ota.cOTA 通道:固件升级分片与校验
apps/common/third_party_profile/Tecent_LL/tecent_protocol/ble_qiot_llsync_event.c事件上报(绑定结果、连接结果、OTA 进度等)
apps/common/third_party_profile/Tecent_LL/include/ble_qiot_llsync_*.h协议常量、枚举、结构体与对外接口声明

消息通道与分发机制

ll_task.c 是整个接入的核心骨架。它定义全局控制块 LL_PACKET_CONTROL LL_packet_c,包含信号量 ll_sem 与环形缓冲 cbuf,并创建独立任务 tecent_ll_task:

static void tecent_ll_task(void *arg)
{
    LL_PACKET_HEAD_T ll_packet_head;
    u8 *buffer = NULL;
    u8 result = 0;
    while (1) {
        os_sem_pend(&(__this->ll_sem), 0);
        if (cbuf_get_data_len(&(__this->cbuf)) > LL_PACKET_HEAD_LEN) {
            cbuf_read(&(__this->cbuf), &ll_packet_head, LL_PACKET_HEAD_LEN);
            buffer = malloc(ll_packet_head.len);
            if (buffer == NULL) {
                printf("buf malloc err\n");
                break;
            }
            cbuf_read(&(__this->cbuf), buffer, ll_packet_head.len);
            switch (ll_packet_head.packet_channel) {
            case LL_DEVICE_INFO_MSG_CH:
                result = ble_device_info_msg_handle(buffer, ll_packet_head.len);
                break;
            case LL_DATA_MSG_CH:
                result = ble_lldata_msg_handle(buffer, ll_packet_head.len);
                break;
            case LL_OTA_MSG_CH:
                result = ble_ota_msg_handle(buffer, ll_packet_head.len);
                break;
            }
            free(buffer);
        }
    }
}

Source: ll_task.c

关键设计点:

  • 包头先行:每个数据包以 LL_PACKET_HEAD_T 开头,任务先读取 LL_PACKET_HEAD_LEN 字节的包头拿到 packet_channel(通道号)与 len(载荷长度),再按 len 动态分配缓冲区读取剩余载荷。这样三种通道共用一个 FIFO,无需为每种消息预分配固定大小缓冲。
  • 通道解耦:switch 按 packet_channel 分发到三个独立处理器,各自维护自己的协议状态机(绑定状态、数据加密会话、OTA 进度),互不干扰。
  • 内存安全:载荷缓冲使用后立即 free;malloc 失败则打印错误并跳出任务(这种异常路径会终止接收循环,实际工程中可改为 continue 以增强健壮性)。

任务初始化与收包入口:

int tecent_ll_task_init(void)
{
    os_sem_create(&(__this->ll_sem), 0);
    u32 malloc_size = (ble_get_user_data_mtu_size() + LL_PACKET_HEAD_LEN) * BLE_QIOT_TOTAL_PACKAGES;
    __this->tecent_ll_buf = malloc(malloc_size);
    memset(__this->tecent_ll_buf, 0x0, malloc_size);
    cbuf_init(&(__this->cbuf), __this->tecent_ll_buf, malloc_size);
    os_task_create(tecent_ll_task, NULL, 1, 512, 0, "tecent_ll_task");
    return 0;
}

void tecent_ll_packet_recieve(void *buf, u16 len)
{
    if (cbuf_is_write_able(&(__this->cbuf), len) >= len) {
        cbuf_write(&(__this->cbuf), buf, len);
    } else {
        printf("[L]\n");
    }
    os_sem_post(&(__this->ll_sem));
}

Source: ll_task.c

  • 缓冲总大小按 (用户数据 MTU + 包头长度)× BLE_QIOT_TOTAL_PACKAGES 计算,保证至少能缓存"单个 MTU 数据包 × 包数上限"的流量,避免高频写入时丢包;
  • tecent_ll_packet_recieve 是 GATT 写回调与任务之间的桥梁:写回调只负责入队 + 发信号量,绝不在中断/协议栈上下文做协议解析;缓冲不可写时打印 [L] 提示丢包;
  • 任务栈 512 字节、优先级 1,属于轻量级接收任务。

应用入口与生命周期

app_ll_sync.c 通过 CONFIG_APP_LL_SYNC 编译开关启用(app_main.c 中对应注册 it.name = "ll_sync"、it.action = ACTION_LL_SYNC),并强约束板级配置:必须开启 BLE 且关闭 EDR,否则编译报错:

#if CONFIG_APP_LL_SYNC

#if !(TCFG_USER_BLE_ENABLE && (!TCFG_USER_EDR_ENABLE))
#error "board config error, confirm!!!!!!"
#endif

Source: app_ll_sync.c

应用状态机在 APP_STA_START 收到 ACTION_LL_SYNC 时启动:

static void llsync_app_start()
{
    log_info("=======================================");
    log_info("-----------ll_sync demo----------------");
    log_info("=======================================");

    log_info("app_file: %s", __FILE__);

    clk_set("sys", BT_NORMAL_HZ);

//有蓝牙
#if TCFG_USER_BLE_ENABLE
    u32 sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
    btstack_ble_start_before_init(NULL, 0);
    btstack_init();
#endif
    /* 按键消息使能 */
    sys_key_event_enable();
}

Source: app_ll_sync.c

启动要点:

  • clk_set("sys", BT_NORMAL_HZ) 将系统时钟切到蓝牙正常模式,随后 bt_pll_para 按晶振频率与系统时钟配置 PLL——腾讯连连需要稳定的 BLE 射频时序,时钟切换是协议栈初始化的前置条件;
  • btstack_ble_start_before_init + btstack_init 完成 BLE 协议栈初始化;
  • sys_key_event_enable 使能按键事件,供演示工程绑定/解绑等交互使用。

llsync_state_machine 处理应用生命周期,llsync_bt_hci_event_handler 把 BLE 连接/断开等 HCI 事件转交给 bt_comm_ble_hci_event_handler 统一处理;llsync_set_soft_poweroff 实现软关机前先 btstack_ble_exit(0) 主动断开链路、再延时 WAIT_DISCONN_TIME_MS 执行 power_set_soft_poweroff,电源事件则通过 sys_event_notify 以 SYS_DEVICE_EVENT / DEVICE_EVENT_FROM_POWER 广播给系统。

GATT 服务、广播与安全配置

ll_sync_demo.c 定义了演示服务的全部 BLE 参数:

//ATT发送的包长,    note: 23 <=need >= MTU
#define ATT_LOCAL_MTU_SIZE        (200)
//ATT缓存的buffer大小,  note: need >= 23,可修改
#define ATT_SEND_CBUF_SIZE        (512)
// 广播周期 (unit:0.625ms)
#define ADV_INTERVAL_MIN          (160 * 5)//

#define LL_TECENT_SUPPORT_TASK       1

Source: ll_sync_demo.c

  • ATT_LOCAL_MTU_SIZE 决定本端 ATT 发送包长上限(200 字节,大于默认 23 字节 MTU),是 LLSync 大包数据的基础;
  • ATT_SEND_CBUF_SIZE 是 ATT 发送缓存,需 ≥ 23;
  • ADV_INTERVAL_MIN = 160 × 5 × 0.625ms = 500ms 为广播最小间隔;
  • LL_TECENT_SUPPORT_TASK 使能任务化收包(对应 ll_task.c)。

连接参数更新表提供三组可选参数,使能开关 llsync_connection_update_enable 默认为 1:

//是否使能参数请求更新,0--disable, 1--enable
static uint8_t llsync_connection_update_enable = 1; ///0--disable, 1--enable
//当前请求的参数表index
//参数表
static const struct conn_update_param_t llsync_connection_param_table[] = {
    {16, 24, 10, 600},//11
    {12, 28, 10, 600},//3.7
    {8,  20, 10, 600},
};

Source: ll_sync_demo.c

广播数据携带腾讯识别 Tag 0xd6 0x05 0x08 0x00 'J' 'L' 'A' 'I' 'S' 'D' 'K'(user_tag_string),"腾讯连连"小程序据此在扫描结果中识别本设备。

安全与 GATT 注册配置:

static const sm_cfg_t llsync_sm_init_config = {
    .slave_security_auto_req = 0,
    .slave_set_wait_security = 0,

#if PASSKEY_ENABLE
    .io_capabilities = IO_CAPABILITY_DISPLAY_ONLY,
#else
    .io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT,
#endif

    .authentication_req_flags = SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION,
    .min_key_size = 7,
    .max_key_size = 16,
    .sm_cb_packet_handler = NULL,
};

const gatt_server_cfg_t llsync_server_init_cfg = {
    .att_read_cb = &llsync_att_read_callback,
    .att_write_cb = &llsync_att_write_callback,
    .event_packet_handler = &llsync_event_packet_handler,
};

static gatt_ctrl_t llsync_gatt_control_block = {
    //public
    .mtu_size = 517,
    .cbuffer_size = 1024,
    .multi_dev_flag	= 0,

Source: ll_sync_demo.c

  • SM 采用 NO_INPUT_NO_OUTPUT(PASSKEY_ENABLE 默认 0),认证标志为 BONDING | MITM,密钥长度 7–16 字节——无配对码的 Just Works 绑定,符合小程序扫码绑定的交互模型;
  • GATT 控制块 mtu_size = 517 为协商后的最大 MTU 预留,cbuffer_size = 1024 为 ATT 收发缓冲,multi_dev_flag = 0 表示单连接模式;
  • llsync_att_write_callback 收到手机写数据后即调用 tecent_ll_packet_recieve 入队(对应 LL_TECENT_SUPPORT_TASK 使能时)。

LLSync 协议定义:设备信息通道

ble_qiot_llsync_device.h 定义了协议版本、绑定状态与设备信息消息类型。协议版本常量与掩码:

#define LLSYNC_BIND_STATE_MASK       0x03
#define LLSYNC_PROTO_VER_BIT         0x04
#define LLSYNC_PROTOCOL_VERSION_MASK 0xF0
#define LLSYNC_MTU_SET_MASK          0x8000

#define LLSYNC_MTU_SET_RESULT_ERR 0xFFFF  // some error when setting mtu

#define BLE_QIOT_LLSYNC_PROTOCOL_VERSION (2)  // llsync protocol version, equal or less than 15

#define ATT_DEFAULT_MTU                 23  // default att mtu
#define ATT_MTU_TO_LLSYNC_MTU(_att_mtu) ((_att_mtu)-3)

#define BLE_LOCAL_PSK_LEN           4
#define BLE_BIND_IDENTIFY_STR_LEN   8
#define BLE_EXPIRATION_TIME         60  // timestamp expiration value
#define BLE_UNBIND_REQUEST_STR      "UnbindRequest"
#define BLE_UNBIND_REQUEST_STR_LEN  (sizeof("UnbindRequest") - 1)
#define BLE_UNBIND_RESPONSE         "UnbindResponse"
#define BLE_UNBIND_RESPONSE_STR_LEN (sizeof("UnbindResponse") - 1)

Source: ble_qiot_llsync_device.h

设计意图:

  • 一个 16 位状态字里用位域同时携带绑定状态(低 2 位)、协议版本位、协议版本号(高 4 位)与 MTU 设置结果(最高位),压缩到单次读特征值即可完成状态上报,减少空中交互次数;
  • BLE_QIOT_LLSYNC_PROTOCOL_VERSION = 2,要求 ≤ 15(与 4 位版本掩码对应);
  • BLE_EXPIRATION_TIME = 60 秒是时间戳签名(timestamp + SHA1)的过期窗口,用于防重放;
  • 绑定前写入 FEE1 特征值的是 ble_bind_data(nonce + timestamp),解绑使用签名串 UnbindRequest/UnbindResponse。

设备信息消息类型枚举覆盖绑定全生命周期与配网:

typedef enum {
    E_DEV_MSG_SYNC_TIME = 0,  // sync info before bind
    E_DEV_MSG_CONN_VALID,     // connect request
    E_DEV_MSG_BIND_SUCC,      // inform bind success
    E_DEV_MSG_BIND_FAIL,      // inform bind failed
    E_DEV_MSG_UNBIND,         // unbind request
    E_DEV_MSG_CONN_SUCC,      // inform connect result
    E_DEV_MSG_CONN_FAIL,
    E_DEV_MSG_UNBIND_SUCC,  // inform unbind result
    E_DEV_MSG_UNBIND_FAIL,
    E_DEV_MSG_SET_MTU_RESULT,  // inform set mtu result
    E_DEV_MSG_BIND_TIMEOUT,    // inform bind timeout
    E_DEV_MSG_GET_DEV_INFO = 0xE0,  // configure network start
    E_DEV_MSG_SET_WIFI_MODE,
    E_DEV_MSG_SET_WIFI_INFO,
    E_DEV_MSG_SET_WIFI_CONNECT,
    E_DEV_MSG_SET_WIFI_TOKEN,
    E_DEV_MSG_GET_DEV_LOG,
    E_DEV_MSG_MSG_BUTT,
} e_dev_info_msg_type;

Source: ble_qiot_llsync_device.h

消息类型分为两段:0x00–0x0B 为绑定/连接/MTU 管理消息(时间同步、连接校验、绑定成功/失败/超时、解绑、MTU 结果);0xE0 起为配网消息(获取设备信息、设置 Wi-Fi 模式/信息/连接/Token、获取设备日志),即设备未入网时通过 BLE 通道完成 Wi-Fi 配置。

绑定与连接状态枚举:

typedef enum {
    E_LLSYNC_BIND_IDLE = 0,  // no bind
    E_LLSYNC_BIND_WAIT,      // wait bind, return idle state if no bind in the period
    E_LLSYNC_BIND_SUCC,      // bound
} e_llsync_bind_state;

typedef enum {
    E_LLSYNC_DISCONNECTED = 0,
    E_LLSYNC_CONNECTED,
} e_llsync_connection_state;

typedef enum {
    E_BLE_DISCONNECTED = 0,
    E_BLE_CONNECTED,
} e_ble_connection_state;

Source: ble_qiot_llsync_device.h

核心数据结构:设备信息(product_id / device_name / psk / mac)、绑定核心数据(local_psk + identify_str)、绑定数据(nonce + timestamp)、连接校验数据(timestamp + SHA1 签名)、解绑数据(SHA1 签名):

typedef struct ble_device_info_t_ {
    char product_id[BLE_QIOT_PRODUCT_ID_LEN];
    char device_name[BLE_QIOT_DEVICE_NAME_LEN + 1];
    char psk[BLE_QIOT_PSK_LEN];
    char mac[BLE_QIOT_MAC_LEN];
} ble_device_info;

typedef struct ble_core_data_ {
    uint8_t bind_state;
    char    local_psk[BLE_LOCAL_PSK_LEN];
    char    identify_str[BLE_BIND_IDENTIFY_STR_LEN];
} ble_core_data;

// write to uuid FEE1 before bind
typedef struct ble_bind_data_t_ {
    int nonce;
    int timestamp;
} ble_bind_data;

// connect data struct
typedef struct ble_conn_data_t_ {
    int  timestamp;
    char sign_info[SHA1_DIGEST_SIZE];
} ble_conn_data;

// unbind data struct
typedef struct ble_unbind_data_t_ {
    char sign_info[SHA1_DIGEST_SIZE];
} ble_unbind_data;

Source: ble_qiot_llsync_device.h

安全模型要点:绑定前手机与设备通过 nonce + timestamp 交换建立共享密钥(local_psk 4 字节 + identify_str 8 字节);绑定后的每次连接使用 timestamp + SHA1(sign_info) 签名校验,BLE_EXPIRATION_TIME=60 秒防止重放攻击。ble_event_slice_t 则用于事件分片上报(BLE_QIOT_EVENT_MAX_SIZE 上限),把大事件拆成多次 GATT 通知。ble_init_flash_data() 负责从 Flash 读取已保存的 SDK 数据(绑定状态、PSK 等),使设备重启后保持绑定关系。

核心流程:小程序绑定到设备

sequenceDiagram
    participant P as 腾讯连连小程序
    participant S as 蓝牙协议栈 (btstack)
    participant W as att_write_callback
    participant T as tecent_ll_task
    participant D as ble_qiot_llsync_device.c

    P->>S: 扫描广播 (EIR Tag 0xd6 0x05 0x08 0x00 'JLAISDK')
    S-->>P: 广播/扫描应答
    P->>S: 发起连接 + 绑定 (Just Works)
    S->>W: GATT Write (FEE1 绑定数据)
    W->>T: tecent_ll_packet_recieve(buf, len) 入 cbuf
    T->>T: os_sem_pend 唤醒, 读包头 packet_channel
    T->>D: ble_device_info_msg_handle (LL_DEVICE_INFO_MSG_CH)
    D->>D: 校验 nonce/timestamp, 生成 local_psk
    D-->>W: 响应包 (绑定结果)
    W-->>P: GATT Notify/Indicate 上报结果
    P->>S: GATT Write (连接校验 timestamp+SHA1)
    S->>T: tecent_ll_packet_recieve 再次入队
    T->>D: 校验签名, 置 E_LLSYNC_BIND_SUCC / 连接态
    D-->>P: 连接成功通知, 进入数据/OTA 通道收发

流程说明:

  1. 设备上电后 llsync_app_start 完成时钟与协议栈初始化,ll_sync_demo.c 启动广播(含腾讯 EIR Tag),小程序扫描识别;
  2. 小程序连接设备并完成 Just Works 绑定(SM_AUTHREQ_BONDING | MITM,NO_INPUT_NO_OUTPUT);
  3. 小程序向绑定特征值写入 ble_bind_data(nonce + timestamp),GATT 写回调仅调用 tecent_ll_packet_recieve 把原始包写入 cbuf 并 os_sem_post;
  4. tecent_ll_task 被唤醒,读取包头得到 LL_DEVICE_INFO_MSG_CH,调用 ble_device_info_msg_handle 完成绑定逻辑(时间同步、PSK 生成);
  5. 处理结果写回 GATT 通知通道,小程序收到绑定成功/失败;
  6. 绑定后每次连接通过 timestamp + SHA1 签名校验(E_DEV_MSG_CONN_VALID),通过后进入数据(LL_DATA_MSG_CH)与 OTA(LL_OTA_MSG_CH)通道正常业务。

绑定状态机

stateDiagram-v2
    [*] --> E_LLSYNC_BIND_IDLE
    E_LLSYNC_BIND_IDLE --> E_LLSYNC_BIND_WAIT: 收到绑定请求 (FEE1 写入)
    E_LLSYNC_BIND_WAIT --> E_LLSYNC_BIND_SUCC: 绑定成功 (E_DEV_MSG_BIND_SUCC)
    E_LLSYNC_BIND_WAIT --> E_LLSYNC_BIND_IDLE: 绑定失败/超时 (BIND_FAIL/BIND_TIMEOUT)
    E_LLSYNC_BIND_SUCC --> E_LLSYNC_BIND_IDLE: 收到解绑 (UnbindRequest)
    E_LLSYNC_BIND_IDLE --> E_LLSYNC_BIND_IDLE: 时间同步/配网消息 (SYNC_TIME/GET_DEV_INFO...)

状态定义见 e_llsync_bind_state(E_LLSYNC_BIND_IDLE → E_LLSYNC_BIND_WAIT → E_LLSYNC_BIND_SUCC),对应消息 E_DEV_MSG_BIND_SUCC/BIND_FAIL/BIND_TIMEOUT;绑定成功态收到 E_DEV_MSG_UNBIND(UnbindRequest 签名)后回到空闲态。ble_core_data.bind_state 持久化于 Flash,设备重启后通过 ble_init_flash_data() 恢复。

使用示例

1. 收包入队(GATT 写回调侧)

任何收到手机数据的通道(绑定、数据、OTA)最终都汇聚到同一入口:

void tecent_ll_packet_recieve(void *buf, u16 len)
{
    if (cbuf_is_write_able(&(__this->cbuf), len) >= len) {
        cbuf_write(&(__this->cbuf), buf, len);
    } else {
        printf("[L]\n");
    }
    os_sem_post(&(__this->ll_sem));
}

Source: ll_task.c

调用方式:ll_sync_demo.c 的 llsync_att_write_callback 在 LL_TECENT_SUPPORT_TASK 使能时把写数据交给本函数,由任务侧统一解析。

2. 任务初始化(应用启动时调用一次)

int tecent_ll_task_init(void)
{
    os_sem_create(&(__this->ll_sem), 0);
    u32 malloc_size = (ble_get_user_data_mtu_size() + LL_PACKET_HEAD_LEN) * BLE_QIOT_TOTAL_PACKAGES;
    __this->tecent_ll_buf = malloc(malloc_size);
    memset(__this->tecent_ll_buf, 0x0, malloc_size);
    cbuf_init(&(__this->cbuf), __this->tecent_ll_buf, malloc_size);
    os_task_create(tecent_ll_task, NULL, 1, 512, 0, "tecent_ll_task");
    return 0;
}

Source: ll_task.c

3. 应用启动(状态机入口)

case APP_STA_START:
    if (!it) {
        break;
    }
    switch (it->action) {
    case ACTION_LL_SYNC:
        llsync_app_start();
        break;
    }
    break;

Source: app_ll_sync.c

4. 软关机(先断链路再断电)

static void llsync_set_soft_poweroff(void)
{
    log_info("set_soft_poweroff\n");
    is_app_llsync_active = 1;
    //必须先主动断开蓝牙链路,否则要等链路超时断开

#if TCFG_USER_BLE_ENABLE
    btstack_ble_exit(0);
    //延时300ms,确保BT退出链路断开
    sys_timeout_add(NULL, power_set_soft_poweroff, WAIT_DISCONN_TIME_MS);
#else
    power_set_soft_poweroff();
#endif
}

Source: app_ll_sync.c

配置选项

以下为 ll_sync_demo.c / app_ll_sync.c 中可直接调整的配置:

选项类型默认值说明
CONFIG_APP_LL_SYNC宏由工程定义使能腾讯连连应用(app_main.c 中映射到 ACTION_LL_SYNC)
TCFG_USER_BLE_ENABLE宏板级配置必须为 1 且 TCFG_USER_EDR_ENABLE 为 0,否则编译报错
ATT_LOCAL_MTU_SIZE宏200本端 ATT 发送包长上限(23 ≤ 值 ≥ MTU)
ATT_SEND_CBUF_SIZE宏512ATT 发送缓存大小(需 ≥ 23)
ADV_INTERVAL_MIN宏160×5 (0.625ms)广播最小间隔,约 500ms
LL_TECENT_SUPPORT_TASK宏1使能任务化收包(走 tecent_ll_task 分发)
PASSKEY_ENABLE宏01 为 Display Only(输入 passkey),0 为 NoInputNoOutput
llsync_connection_update_enableu81是否使能连接参数请求更新
llsync_connection_param_table[]数组{16,24,10,600} 等 3 组连接参数候选表(min/max interval, latency, timeout)
llsync_gatt_control_block.mtu_sizeu16517GATT 协商 MTU 预留值
llsync_gatt_control_block.cbuffer_sizeu161024ATT 收发缓冲
llsync_gatt_control_block.multi_dev_flagu80单连接模式
BLE_QIOT_LLSYNC_PROTOCOL_VERSION宏2LLSync 协议版本(≤ 15)
BLE_EXPIRATION_TIME宏60 (s)时间戳签名过期窗口

API 参考

int tecent_ll_task_init(void)

初始化腾讯连连接收任务:创建信号量、按 (用户数据 MTU + 包头) × BLE_QIOT_TOTAL_PACKAGES 分配环形缓冲、创建 tecent_ll_task 任务(优先级 1,栈 512 字节)。

返回: 恒为 0(成功)。

void tecent_ll_packet_recieve(void *buf, u16 len)

将收到的原始 LLSync 数据包写入环形缓冲并唤醒任务。须在 GATT 写回调中调用,不得在中断上下文做协议解析。

  • buf:收到的数据包指针;
  • len:数据长度;
  • 缓冲不可写时打印 [L] 并丢弃该包,随后仍会 os_sem_post(任务侧因长度不足不会处理)。

u8 ble_device_info_msg_handle(u8 *buffer, u16 len)

设备信息通道处理器(绑定/解绑/配网/MTU 协商),由 tecent_ll_task 在 LL_DEVICE_INFO_MSG_CH 分支调用。实现见 tecent_protocol/ble_qiot_llsync_device.c。

u8 ble_lldata_msg_handle(u8 *buffer, u16 len)

业务数据通道处理器(LLSync 数据加解密收发),LL_DATA_MSG_CH 分支调用。实现见 tecent_protocol/ble_qiot_llsync_data.c。

u8 ble_ota_msg_handle(u8 *buffer, u16 len)

OTA 通道处理器(固件升级分片与校验),LL_OTA_MSG_CH 分支调用。实现见 tecent_protocol/ble_qiot_llsync_ota.c。

ble_qiot_ret_status_t ble_init_flash_data(void)

从 Flash 读取 SDK 持久化数据(绑定状态、local_psk、identify_str 等),设备重启后恢复绑定关系。声明见 ble_qiot_llsync_device.h。

失败模式与边界情况

  • 环形缓冲溢出(丢包):tecent_ll_packet_recieve 在 cbuf 不可写时打印 [L] 并丢弃数据。高吞吐数据(如 OTA 分片连续下发)或 MTU 较大时易触发;缓解手段是保证 tecent_ll_task_init 分配的缓冲容量 (MTU + 包头) × BLE_QIOT_TOTAL_PACKAGES 大于单次突发流量,并确认任务调度及时。
  • malloc 失败导致任务退出:tecent_ll_task 中 malloc(ll_packet_head.len) 失败会 break 退出接收循环,此后该任务不再处理任何包。实际产品建议改为 continue 并做错误计数,避免协议栈静默失效。
  • 包头长度异常:任务只校验 cbuf_get_data_len > LL_PACKET_HEAD_LEN,未校验 ll_packet_head.len 是否超出缓冲/合理范围;若手机端发送畸形包(如超大 len),malloc 可能失败或产生大块内存申请。
  • 未知通道号:switch 无 default 分支,未知 packet_channel 的包被读取后直接丢弃(buffer 仍被 free,不会泄漏)。
  • 时间戳过期:BLE_EXPIRATION_TIME = 60 秒,绑定/连接签名中的 timestamp 超出窗口即拒绝,防止重放;设备与手机时钟偏差过大时会导致绑定失败,需先完成 E_DEV_MSG_SYNC_TIME 时间同步。
  • 并发与上下文:GATT 写回调与 tecent_ll_task 之间通过"cbuf 写 + 信号量"同步,是经典的单生产者单消费者模型,无需锁;但 ble_*_msg_handle 内部若操作共享状态(如绑定状态、OTA 进度),需保证只在任务上下文访问。
  • 软关机竞态:llsync_set_soft_poweroff 先 btstack_ble_exit(0) 断开链路,再延时 WAIT_DISCONN_TIME_MS 执行 power_set_soft_poweroff;若断电提前发生,链路可能未完全释放,影响下次开机。

性能与运维要点

  • 任务化隔离:所有协议解析(HMAC/SHA1 签名校验、加解密、OTA 分片重组)都在 tecent_ll_task(优先级 1,栈 512B)中执行,BLE 协议栈不会被长任务阻塞;若后续 OTA 校验逻辑加重,可适当提高任务优先级或栈大小。
  • MTU 与吞吐:ATT_LOCAL_MTU_SIZE = 200、GATT 控制块 mtu_size = 517、cbuffer_size = 1024 决定了单包数据量与收发吞吐;调大 MTU 可减少 OTA 分片数,但会增大内存占用。
  • 连接参数:三组候选参数(如 {16,24,10,600} 对应约 10ms 间隔)由 llsync_connection_update_enable 控制请求更新,低间隔参数降低交互时延,适合控制类指令;功耗敏感场景可选择更大间隔组。
  • 日志:app_ll_sync.c 使用 LOG_TAG "[LLSYNC]" 的 debug.h 日志体系(log_info/log_error);ll_sync_demo.c 提供 [BLE_llsync] 前缀打印与 put_buf 十六进制 dump,便于联调抓包对照。

扩展点

  • 新增消息通道:在 ll_task.c 的 switch 中增加 case 分支,并在 ll_task.h 定义新的 packet_channel 常量与包头结构,即可扩展自定义通道(如设备日志、量产测试指令)。
  • 配网/业务回调:设备信息通道中的 E_DEV_MSG_SET_WIFI_INFO/CONNECT/TOKEN 等消息在 ble_qiot_llsync_device.c 处理,接入方可在其中挂接自己的 Wi-Fi 模组驱动;ble_qiot_llsync_event.c 的事件上报接口用于把设备端结果回传小程序。
  • 协议版本升级:BLE_QIOT_LLSYNC_PROTOCOL_VERSION 与 LLSYNC_PROTOCOL_VERSION_MASK/LLSYNC_PROTO_VER_BIT 支持版本协商,升级腾讯 SDK 时保持版本字段一致即可兼容新旧小程序。
  • 演示替换:apps/spp_and_le/examples/ll_sync/ 是纯演示工程,量产接入时可在 llsync_att_write_callback/llsync_att_read_callback 与 tecent_ll_packet_recieve 之间插入自己的鉴权或日志逻辑,不必改动 SDK 协议层。

相关链接

  • ll_task.c(任务分发骨架)
  • ll_sync_demo.c(GATT 服务演示)
  • app_ll_sync.c(应用入口)
  • ble_qiot_llsync_device.h(协议定义)
  • Tecent_LL SDK 目录
  • 腾讯云 IoT 官方 LLSync 文档(外部):https://cloud.tencent.com/document/product/1081
Prev
涂鸦协议接入
Next
华为 HiLink 接入