杰理 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)
  • 文档与开发资源

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

杰理 RCSP 私有协议

杰理(Jieli)RCSP(Remote Control & Streaming Protocol)是杰理科技为其蓝牙 SoC 定义的私有应用控制协议,运行于 BLE 或 SPP 传输通道之上,用于手机 APP(如杰理之家/BTMATE)与设备之间完成鉴权、状态查询、EQ 调节、文件浏览与传输、OTA 升级、运动数据同步等操作。本页介绍该协议在 fw-AC63_BT_SDK 中的分层实现、数据包格式、命令码体系、鉴权流程及应用层集成方式。

Purpose and Scope

本页面向需要理解或扩展 RCSP 协议栈的嵌入式开发者,涵盖:

  • RCSP 协议在 SDK 中的三层架构(packet 层 / protocol 层 / 应用集成层)与依赖关系
  • JL_PACKET 数据包格式、头部位域、MTU 与内存池配置
  • 命令码(OpCode)、属性类型(AttrType)与回调接口 JL_PRO_CB
  • 设备端鉴权(auth)机制与 AI 平台扩展(图灵/深兰)
  • 应用层集成入口 rcsp_bluetooth.c:通道选择、功能掩码、设备信息上报
  • 发送/接收 API 参考、失败模式与扩展点

以下内容不属于本页范围,请参阅对应目录页:RCSP OTA 升级链路(rcsp_user_update.c/rcsp_ch_loader_download.c,参见「RCSP 升级」相关文档)、HID 透传(rcsp_hid_inter.c)、消息分发(rcsp_msg.h)。RCSP 协议栈本体以预编译静态库 rcsp_stack.a 提供(见 cpu/*/liba/),头文件为公开接口契约,本页所有 API 均以这些头文件为准。

Overview

RCSP 的本质是一个请求/响应型的主从私有协议:手机 APP 作为主设备(Master)发起命令,蓝牙设备作为从设备(Slave)解析并应答。与标准 SPP/BLE 透传不同,RCSP 在传输层之上增加了:

  1. 数据包封装:以 0xFE 0xDC 0xBA 起始标签 + 头部位域 + 长度 + 负载 + 结束标签 0xEF 组成定界帧,解决字节流粘包/半包问题;
  2. 命令/数据两类消息:JL_CMD_* 用于控制类命令,JL_DATA_* 用于大块数据(如文件传输、运动数据),二者各自独立地支持"需要应答/无需应答"两种模式;
  3. 设备鉴权:APP 首次连接须完成 link key 校验(JL_rcsp_auth_init),未通过鉴权时协议栈拒绝大部分命令;
  4. 属性化的信息模型:系统信息(电量、音量、设备句柄)、蓝牙音乐信息(标题、歌手、时长)、EQ 信息等均以 ATTR_TYPE_* 属性码标识,通过 JL_OPCODE_SYS_INFO_GET/SET/AUTO_UPDATE 读写。

SDK 中的传输通道由宏 RCSP_CHANNEL_SEL 决定:RCSP_USE_BLE(0,默认)走 BLE GATT,RCSP_USE_SPP(1)走经典蓝牙 SPP。无论哪种通道,上层协议处理逻辑一致,通道差异被协议栈的 fw_send 回调屏蔽。

Architecture

flowchart TD
    subgraph sg_App["手机 APP 侧(主设备)"]
        APP["杰理之家 / BTMATE APP"]
    end

    subgraph sg_Transport["传输通道"]
        BLE["BLE GATT<br/>RCSP_CHANNEL_SEL = 0"]
        SPP["SPP<br/>RCSP_CHANNEL_SEL = 1"]
    end

    subgraph sg_Stack["RCSP 协议栈(预编译 rcsp_stack.a)"]
        PKT["JL_rcsp_packet.h<br/>JL_PACKET 封装/解析<br/>MTU 与内存池"]
        PROTO["JL_rcsp_protocol.h<br/>命令分发/应答/鉴权<br/>JL_PRO_CB 回调"]
        AUTH["JL_rcsp_api.h<br/>鉴权初始化/状态"]
    end

    subgraph sg_AppLayer["设备端应用集成层"]
        RCSPBT["rcsp_bluetooth.c<br/>功能掩码/设备信息/命令处理"]
        UPDATE["rcsp_user_update.c<br/>OTA 升级"]
        HID["rcsp_hid_inter.c<br/>HID 透传"]
        MSG["rcsp_msg.h<br/>消息分发"]
    end

    subgraph sg_Device["设备子系统"]
        AVCTP["AVCTP 音乐控制"]
        FM["FM 发射/接收"]
        UI["UI 界面"]
        FLASH["Flash/文件系统"]
    end

    APP -->|"BLE/SPP 连接"| BLE
    APP -->|"BLE/SPP 连接"| SPP
    BLE --> PKT
    SPP --> PKT
    PKT --> PROTO
    PROTO --> AUTH
    PROTO -->|"CMD/DATA 回调"| RCSPBT
    RCSPBT --> UPDATE
    RCSPBT --> HID
    RCSPBT --> MSG
    RCSPBT --> AVCTP
    RCSPBT --> FM
    RCSPBT --> UI
    RCSPBT --> FLASH

架构说明:APP 通过 BLE(默认)或 SPP 接入设备。字节流首先进入 packet 层完成定界与重组,形成完整的 JL_PACKET;随后 protocol 层根据头部 OpCode/type 位域分发到命令或数据处理器,并回调到应用层注册的 JL_PRO_CB 函数指针;应用层 rcsp_bluetooth.c 作为总入口,把协议命令翻译成对 AVCTP、FM、UI、文件系统等设备子系统的操作,并将结果经 protocol 层的 JL_CMD_response_send 封装成应答包回传 APP。鉴权状态由 JL_rcsp_api.h 的接口维护,未通过鉴权时协议栈拒绝执行命令。

数据包格式:JL_PACKET

RCSP 所有消息统一封装为 JL_PACKET 结构,定义于 JL_rcsp_packet.h:

#pragma pack(1)
typedef union __HEAD_BIT {
    struct {
        u16 _OpCode: 8; //OpCode val
        u16 _unsed : 6; //unsed
        u16 _resp : 1; //request for response
        u16 _type : 1; //command or response
    } _i;
    u16         _t;
} HEAD_BIT;

struct __JL_PACKET {
    u8          tag[3];
    HEAD_BIT    head;
    u16         length;
    u8          data[0];
};
#pragma pack()
typedef struct __JL_PACKET JL_PACKET;

来源:JL_rcsp_packet.h

关键设计点:

  • 起始/结束标签:起始标签固定为 0xFE 0xDC 0xBA,结束标签为 0xEF(见 JL_PACK_START_TAG0/1/2 与 JL_PACK_END_TAG),用于接收端在字节流中找帧边界;
  • 16 位头部位域:低 8 位为 OpCode 命令码;第 9 位为 _type(0 = 命令/请求,1 = 应答);第 10 位为 _resp(1 = 请求应答);其余 6 位保留。位域被打包进 u16 _t,配合 #pragma pack(1) 保证无填充字节,sizeof(JL_PACKET) 恒为 7(3 字节 tag + 2 字节 head + 2 字节 length);
  • 零长数组负载:data[0] 为柔性数组,JL_ONE_PACKET_LEN(n) 宏按 sizeof(JL_PACKET) + n + 1(+1 为结束标签)计算整包长度。
flowchart LR
    subgraph sg_Frame["RCSP 帧结构"]
        T0["tag[0] = 0xFE"]
        T1["tag[1] = 0xDC"]
        T2["tag[2] = 0xBA"]
        H["head (u16)<br/>OpCode[7:0] | resp | type"]
        L["length (u16)"]
        D["data[len]"]
        TE["0xEF"]
    end
    T0 --> T1 --> T2 --> H --> L --> D --> TE

字节序与读写宏

协议栈支持大小端两种字节序,由 JL_rcsp_api.h 的 USE_ENDIAN_TYPE 控制(默认 USE_LITTLE_ENDIAN),并配套提供 app_htons/app_ntohs/app_htonl/app_ntohl 主机序转换函数。packet 层则提供独立的读写宏(JL_rcsp_packet.h):

#define READ_BIG_U16(a)   ((*((u8*)(a)) <<8)  + *((u8*)(a)+1))
#define READ_LIT_U32(a)   (*((u8*)(a))  + (*((u8*)(a)+1)<<8) + (*((u8*)(a)+2)<<16) + (*((u8*)(a)+3)<<24))

#define WRITE_BIG_U32(a,src)   {*((u8*)(a)+0) = (u8)((src)>>24);  *((u8*)(a)+1) = (u8)(((src)>>16)&0xff);*((u8*)(a)+2) = (u8)(((src)>>8)&0xff);*((u8*)(a)+3) = (u8)((src)&0xff);}
#define WRITE_LIT_U16(a,src)   {*((u8*)(a)+1) = (u8)(src>>8); *((u8*)(a)+0) = (u8)(src&0xff); }

来源:JL_rcsp_packet.h

这些宏被协议栈内部用于解析/组装负载字段,应用层在构造自定义命令负载时也应复用它们,以保证与协议栈的字节序策略一致。

协议层:命令码与属性体系

命令码(OpCode)

命令码定义于 JL_rcsp_protocol.h,头文件注释特别强调该枚举不可插入新值(协议兼容性约束),扩展请使用保留区 JL_OPCODE_CUSTOMER_USER = 0xFF。主要命令分类如下:

命令码值用途
JL_OPCODE_DATA0x01通用数据通道
JL_OPCODE_GET_TARGET_FEATURE_MAP / _FEATURE0x02 / 0x03查询目标特性位图/特性
JL_OPCODE_DISCONNECT_EDR0x06断开经典蓝牙(EDR)连接
JL_OPCODE_SYS_INFO_GET / _SET / _AUTO_UPDATE0x07 / 0x08 / 0x09系统信息读/写/主动上报
JL_OPCODE_CALL_REQUEST0x0A通话请求
JL_OPCODE_SWITCH_DEVICE0x0B切换设备
JL_OPCODE_FILE_BROWSE_REQUEST_START / _STOP0x0C / 0x0D文件浏览启停
JL_OPCODE_FUNCTION_CMD0x0E功能命令(音乐/线控等)
JL_OPCODE_SYS_OPEN_BT_SCAN / _STOP_BT_SCAN0x12 / 0x14开启/停止蓝牙扫描
JL_OPCODE_SYS_UPDATE_BT_STATUS0x13更新蓝牙状态
JL_OPCODE_SYS_BT_CONNECT_SPEC0x15连接指定蓝牙地址
JL_OPCODE_SYS_FIND_DEVICE0x19查找设备
JL_OPCODE_EXTRA_FLASH_OPT0x1AFlash 扩展操作
JL_OPCODE_FILE_TRANSFER_START / _END / _TRANSFER / _CANCEL0x1B–0x1E文件传输生命周期
JL_OPCODE_FILE_DELETE / _RENAME0x1F / 0x20文件删除/重命名
JL_OPCODE_ACTION_PREPARE0x21APP 操作预处理
JL_OPCODE_DEVICE_FORMAT0x22设备格式化
JL_OPCODE_ONE_FILE_DELETE / _TRANS_BACK0x23 / 0x24删除/回传单个文件
JL_OPCODE_FILE_BLUK_TRANSFER0x26批量大文件传输准备
JL_OPCODE_DEVICE_PARM_EXTRA0x27设备操作参数扩展
JL_OPCODE_SIMPLE_FILE_TRANS0x28简单文件传输
JL_OPCODE_SPORTS_DATA_INFO_* / SENSOR_*0xA0–0xA6运动/传感器数据同步
JL_OPCODE_NOTIFY_MTU0xD1MTU 通知
JL_OPCODE_GET_MD50xD4获取 MD5
JL_OPCODE_LOW_LATENCY_PARAM0xD5低延迟参数
JL_OPCODE_CUSTOMER_USER0xFF客户自定义命令区

属性类型(AttrType)

系统信息类属性(JL_rcsp_protocol.h):

属性值含义
ATTR_TYPE_PROTOCOL_VERSION0协议版本
ATTR_TYPE_SYS_INFO1系统信息(电量/音量等)
ATTR_TYPE_EDR_ADDR2经典蓝牙地址
ATTR_TYPE_PLATFORM3AI 平台
ATTR_TYPE_FUNCTION_INFO4功能位图
ATTR_TYPE_DEV_VERSION / SDK_TYPE / UBOOT_VERSION5/6/7版本信息
ATTR_TYPE_DOUBLE_PARITION8双分区标志
ATTR_TYPE_UPDATE_STATUS9升级状态
ATTR_TYPE_DEV_VID_PID / AUTHKEY / PROCODE / MAX_MTU10–13设备标识与能力
ATTR_TYPE_MD5_GAME_SUPPORT19MD5 游戏支持

通用信息属性(COMMON_INFO_ATTR_*,0–15)覆盖电池、音量、设备句柄、错误上报、EQ、文件浏览类型、功能类型、灯光、FM 发射、高低音设置、ANC 语音、Phone SCO 状态等;蓝牙音乐属性(BT_INFO_ATTR_*,0–8)覆盖歌名、歌手、专辑、曲目序号、总时长、流派、播放状态与当前时间;此外还有 MUSIC_INFO_ATTR_*、RTC_INFO_ATTR_*、LINEIN_INFO_ATTR_* 分别描述音乐播放、RTC 时钟/闹钟与 Line-in 状态。这套属性化模型使 APP 通过 SYS_INFO_GET/SET/AUTO_UPDATE 三个命令即可统一读写所有设备信息,避免为每个状态项定义独立命令。

应答状态与错误码

协议层定义了两套状态枚举(JL_rcsp_protocol.h):

typedef enum __JL_ERR {
    JL_ERR_NONE = 0x0,
    JL_ERR_SEND_DATA_OVER_LIMIT,
    JL_ERR_SEND_BUSY,
    JL_ERR_SEND_NOT_READY,
    JL_ERR_EXIT,
} JL_ERR;

typedef enum __JL_PRO_STATUS {
    JL_PRO_STATUS_SUCCESS = 0x0,
    JL_PRO_STATUS_FAIL,
    JL_PRO_STATUS_UNKOWN_CMD,
    JL_PRO_STATUS_BUSY,
    JL_PRO_STATUS_NO_RESPONSE,
    JL_PRO_STATUS_CRC_ERR,
    JL_PRO_STATUS_ALL_DATA_CRC_ERR,
    JL_PRO_STATUS_PARAM_ERR,
    JL_PRO_STATUS_RESP_DATA_OVER_LIMIT,
} JL_PRO_STATUS;

来源:JL_rcsp_protocol.h

JL_ERR 是协议栈内部发送函数的返回值(本地错误),JL_PRO_STATUS 是随应答包返回给 APP 的远端状态码(如未知命令、CRC 错误、参数错误、应答超限),二者在调试协议交互时需区分对待。

核心流程:命令下发与应答

RCSP 的端到端消息流如下:APP 命令经传输通道到达设备后,packet 层先完成定界组包,protocol 层再按类型分发,最后应用层回调处理并回发应答。

sequenceDiagram
    participant APP as 手机 APP(主设备)
    participant CH as 传输通道 BLE/SPP
    participant PKT as JL_packet 层
    participant PRO as JL_protocol 层
    participant APPDEV as 应用层 rcsp_bluetooth.c

    APP->>CH: 发送 RCSP 帧(tag + head + data + 0xEF)
    CH->>PKT: JL_packet_recieve(buf, len)
    PKT->>PKT: JL_packet_find 找帧边界/校验
    PKT->>PRO: 完整 JL_PACKET
    PRO->>PRO: 解析 head 位域(OpCode/type/resp)
    alt 鉴权未通过
        PRO-->>APP: 拒绝执行(JL_AUTH_NOTPASS)
    else 鉴权通过
        PRO->>APPDEV: CMD_resp / CMD_no_resp 回调
        APPDEV->>APPDEV: 翻译为设备子系统操作(AVCTP/FM/UI...)
        APPDEV-->>PRO: 处理结果 + 应答数据
        PRO-->>APP: JL_CMD_response_send 应答帧
    end

入口函数:传输层把收到的字节流交给 JL_packet_recieve(void *buf, u16 len)(JL_rcsp_packet.h);组包完成后由 JL_protocol_data_recieve(void *priv, void *buf, u16 len) 进入协议层(JL_rcsp_protocol.h)。协议层主循环由 JL_protocol_process() 驱动,发送队列与接收解析分别由 JL_send_packet_process() 和 JL_recieve_packet_parse_process() 处理,应用层需在系统定时器中周期调用,以保证待发队列不被饿死、应答超时能被检测。

回调接口 JL_PRO_CB

应用层通过注册 JL_PRO_CB 结构接收协议事件(JL_rcsp_protocol.h):

typedef struct __JL_PRO_CB {
    /*send function callback, SPP or ble*/
    void *priv;
    bool (*fw_ready)(void *priv);
    s32(*fw_send)(void *priv, void *buf, u16 len);
    /*JL_CMD、JL_CMD_response、JL_DATA、JL_DATA_response packet recieve callback*/
    void (*CMD_resp)(void *priv, u8 OpCode, u8 OpCode_SN, u8 *data, u16 len);
    void (*DATA_resp)(void *priv, u8 OpCode_SN, u8 CMD_OpCode, u8 *data, u16 len);
    void (*CMD_no_resp)(void *priv, u8 OpCode, u8 *data, u16 len);
    void (*DATA_no_resp)(void *priv, u8 CMD_OpCode, u8 *data, u16 len);
    void (*CMD_recieve_resp)(void *priv, u8 OpCode, u8 status, u8 *data, u16 len);
    void (*DATA_recieve_resp)(void *priv, u8 status, u8 CMD_OpCode, u8 *data, u16 len);
    u8(*wait_resp_timeout)(void *priv, u8 OpCode, u8 counter);
    void (*auth_pass_callback)(void *priv);
} JL_PRO_CB;

来源:JL_rcsp_protocol.h

回调分工:

  • fw_ready / fw_send:通道就绪查询与底层字节发送,priv 携带通道上下文,从而把 SPP/BLE 差异隔离在协议栈之外;
  • CMD_resp / CMD_no_resp:收到需要应答/无需应答的命令(JL_CMD_* 请求);
  • DATA_resp / DATA_no_resp:收到需要/无需应答的数据消息(JL_DATA_*);
  • CMD_recieve_resp / DATA_recieve_resp:收到远端对本机先前请求的应答;
  • wait_resp_timeout:等待应答超时回调,counter 为重试计数,可据此实现重发策略;
  • auth_pass_callback:鉴权通过通知,应用层在此之后才允许执行受保护命令。

JL_protocol_dev_switch(const JL_PRO_CB *cb) 用于切换当前生效的回调组(如从 BLE 通道切到 SPP 通道)。

鉴权机制

RCSP 在建立业务会话前强制鉴权,接口位于 JL_rcsp_api.h:

void JL_rcsp_auth_init(int (*send)(void *, u8 *, u16), u8 *link_key, u8 *addr);
void JL_rcsp_auth_reset(void);
u8 JL_rcsp_get_auth_flag(void);
void JL_rcsp_set_auth_flag(u8 auth_flag);
void JL_rcsp_auth_recieve(u8 *buffer, u16 len);

来源:JL_rcsp_api.h

鉴权状态枚举为 JL_AUTH_NOTPASS(0)与 JL_AUTH_PASS(1)。JL_rcsp_auth_init 接收发送函数、link key 与设备地址,鉴权成功后协议栈会调用 JL_PRO_CB.auth_pass_callback。JL_rcsp_auth_recieve 负责处理 APP 发来的鉴权数据帧,整个握手过程对应用层透明——应用层只需在连接建立时初始化鉴权并监听 auth_pass_callback。

stateDiagram-v2
    [*] --> 未鉴权: 连接建立
    未鉴权 --> 鉴权中: JL_rcsp_auth_init<br/>收到 auth 帧
    鉴权中 --> 已鉴权: link key 校验通过<br/>(auth_pass_callback)
    鉴权中 --> 未鉴权: 校验失败/超时<br/>JL_rcsp_auth_reset
    已鉴权 --> 未鉴权: 断开连接

设计意图:鉴权放在协议层而非应用层,可保证所有通过 JL_CMD_send 等协议入口发出的受保护命令天然受到约束,应用层开发者不必在每个命令处理函数里重复做权限判断;同时 link_key 按设备绑定,防止非授权 APP 直接操控设备。

应用层集成:rcsp_bluetooth.c

rcsp_bluetooth.c(源码)是设备端 RCSP 功能的总装配点,整个文件受 #if (RCSP_BTMATE_EN) 宏保护,未使能时全部代码不参与编译。

通道选择与全局状态

#define RCSP_USE_BLE      0
#define RCSP_USE_SPP      1
#define RCSP_CHANNEL_SEL  RCSP_USE_BLE

struct JL_AI_VAR jl_ai_var = {
    .rcsp_run_flag = 0,
};

#define __this (&jl_ai_var)

来源:rcsp_bluetooth.c

RCSP_CHANNEL_SEL 决定底层走 BLE(默认)还是 SPP;jl_ai_var 是全局运行状态(rcsp_run_flag),通过 __this 宏在模块内统一访问。同文件顶部还定义了 TULING_AI_EN/DEEPBRAN_AI_EN(图灵/深兰 AI 平台开关)与 RCSP_DEBUG_EN 调试开关(开启后 rcsp_printf/rcsp_printf_buf 输出协议调试信息)。

功能掩码与设备信息模型

#define BT_FUNCTION        0
#define MUSIC_FUNCTION     1
#define RTC_FUNCTION       2
#define LINEIN_FUNCTION    3
#define FM_FUNCTION        4
#define LIGHT_FUNCTION     5
#define FMTX_FUNCTION      6

#define FUNCTION_INFO  (BIT(MUSIC_FUNCTION_MASK) | BIT(LINEIN_FUNCTION_MASK) | BIT(RTC_FUNCTION_MASK) | BIT(FMTX_FUNCTION_MASK))

#pragma pack(1)

struct _SYS_info {
    u8 bat_lev;
    u8 sys_vol;
    u8 max_vol;
    u8 reserve;
};

struct _EDR_info {
    u8 addr_buf[6];
    u8 profile;
    u8 state;
};

struct _DEV_info {
    u8 status;
    u32 usb_handle;
    u32 sd0_handle;
    u32 sd1_handle;
    u32 flash_handle;
};

struct _EQ_INFO {
    u8 mode;
    s8 gain_val[10];
};

struct _MUSIC_STATUS_info {
    u8 status;
    u32 cur_time;
    u32 total_time;
    u8 cur_dev;
};

来源:rcsp_bluetooth.c

这些 1 字节对齐的结构体直接对应 JL_OPCODE_SYS_INFO_GET/SET 命令的负载格式:_SYS_info 上报电量/音量,_EDR_info 上报经典蓝牙地址与连接状态,_DEV_info 上报 USB/SD0/SD1/Flash 各存储设备的句柄,_EQ_INFO 携带 EQ 模式与 10 段增益,_MUSIC_STATUS_info 描述播放状态与进度。FUNCTION_INFO 位图则通过 ATTR_TYPE_FUNCTION_INFO 属性告知 APP 本设备支持哪些功能(音乐/Line-in/RTC/FM 发射),APP 据此动态显示控制面板——这是"属性化信息模型"在应用层的具体落地。

AI 平台扩展

#define AI_LICENCE_LEN    16

enum {
    TULING = 0,
    DEEPBRAIN,
};

#pragma pack(1)
struct _AI_platform {
    u8 platform;
    u8 license[AI_LICENCE_LEN];
};
#pragma pack()

来源:JL_rcsp_api.h

_AI_platform 由 get_ai_platform(struct _AI_platform *p, u8 platform) 填充,license 为 16 字节 AI 授权码,配合 ATTR_TYPE_PLATFORM 属性与 JL_OPCODE_SYS_INFO_SET 完成 AI 平台切换与授权写入,供语音助手类功能使用。

配置选项

选项类型默认值说明
RCSP_BTMATE_EN宏由板级配置决定RCSP 总开关,关闭后 rcsp_bluetooth.c 整体不编译
RCSP_CHANNEL_SEL宏RCSP_USE_BLE (0)传输通道:0 = BLE GATT,1 = SPP
RCSP_DEBUG_EN宏定义协议调试打印开关(rcsp_printf/put_buf)
TULING_AI_EN / DEEPBRAN_AI_EN宏0 / 1AI 平台使能:图灵 / 深兰
USE_ENDIAN_TYPE宏USE_LITTLE_ENDIAN协议负载字节序(大端/小端)
JL_MTU_RESV宏540接收侧保留 MTU(协议栈解析能力上限)
JL_MTU_SEND宏128发送 MTU(单包最大发送负载)
JL_RECIEVE_BUF_SIZE宏JL_MTU_RESV + sizeof(JL_PACKET) + 128接收缓冲大小(uboot 版本为 ×2)
JL_CMD_POOL_SIZE宏JL_MTU_SEND*4命令缓冲池(uboot 版本为 JL_MTU_SEND)
JL_RESP_POOL_SIZE宏JL_MTU_SEND*2应答缓冲池(uboot 版本同值)
JL_WAIT_RESP_POOL_SIZE宏JL_MTU_SEND*2等待应答缓冲池(uboot 版本为 JL_MTU_SEND)

池大小宏位于 JL_rcsp_packet.h,在 JL_RCSP_UBOOT_LIB 宏(uboot 阶段加载器)下自动切换到紧凑配置以节省 RAM。运行时还可通过 set_jl_mtu_resv() / set_jl_mtu_send() / set_jl_rcsp_recieve_buf_size() 动态调整,JL_packet_set_mtu(u16 mtu) 返回协商后的 MTU,配合 JL_OPCODE_NOTIFY_MTU 命令实现与 APP 的 MTU 协商。

API 参考

发送接口(协议层)

JL_ERR JL_CMD_send(u8 OpCode, u8 *data, u16 len, u8 request_rsp);
JL_ERR JL_CMD_response_send(u8 OpCode, u8 status, u8 sn, u8 *data, u16 len);
JL_ERR JL_DATA_send(u8 OpCode, u8 CMD_OpCode, u8 *data, u16 len, u8 request_rsp);
JL_ERR JL_DATA_response_send(u8 OpCode, u8 status, u8 sn, u8 CMD_OpCode, u8 *data, u16 len);

来源:JL_rcsp_protocol.h

  • Parameters: OpCode 命令码;status 应答状态(JL_PRO_STATUS_*);sn 应答序号(对应请求帧的序号,用于请求-应答配对);CMD_OpCode 数据消息关联的命令码;request_rsp 为 JL_NEED_RESPOND/JL_NOT_NEED_RESPOND;data/len 为负载。
  • Returns: JL_ERR_NONE 成功;JL_ERR_SEND_DATA_OVER_LIMIT 负载超过 MTU;JL_ERR_SEND_BUSY 发送队列忙;JL_ERR_SEND_NOT_READY 通道未就绪;JL_ERR_EXIT 协议栈已退出。

接收与生命周期(协议层)

void JL_protocol_init(u8 *buf, u32 len);        // 用外部内存初始化协议栈
void JL_protocol_exit(void);                    // 释放/退出协议栈
void JL_protocol_data_recieve(void *priv, void *buf, u16 len); // 注入传输层数据
void JL_protocol_process(void);                 // 协议主循环(需周期调用)
void JL_protocol_resume(void);                  // 恢复处理
void JL_protocol_dev_switch(const JL_PRO_CB *cb); // 切换回调组(通道切换)
void JL_set_cur_tick(u16 tick);                 // 喂入当前时间戳(超时计算)
void set_auth_pass(u8 auth_pass);               // 设置鉴权通过标志
bool rcsp_send_list_is_empty(void);             // 发送队列是否为空(休眠判定)

来源:JL_rcsp_protocol.h

数据包接口(packet 层)

u32 rcsp_packet_need_buf_size(void);            // 计算协议栈所需内存总大小
u32 rcsp_packet_buf_init(u8 *buf, u32 len);     // 用给定内存初始化 packet 池
void JL_packet_init(void); / void JL_packet_clear(void);
void JL_packet_recieve(void *buf, u16 len);     // 接收原始字节流
bool JL_packet_find(u8 *r_buf, JL_PACKET **packet); // 在缓冲中查找完整帧
u32 JL_pack_data_read_all(void *buf, u16 len);  // 读出已解析数据
void JL_packet_clear_all_data(void);
void JL_packet_packing(JL_PACKET *packet, u8 OpCode, u8 type, u8 request_rsp,
                       u8 *extra_param, u16 extra_len, u8 *data, u16 len); // 组装帧
u16 JL_packet_get_rx_max_mtu(void); / u16 JL_packet_get_tx_max_mtu(void);
u16 JL_packet_set_mtu(u16 mtu);                 // 协商 MTU,返回生效值

来源:JL_rcsp_packet.h

失败模式、边界与并发

  • 发送失败分类:JL_ERR 枚举将发送失败细分为超限(SEND_DATA_OVER_LIMIT)、队列忙(SEND_BUSY)、通道未就绪(SEND_NOT_READY)与协议栈退出(EXIT)。应用层应在 SEND_BUSY 时重试而非丢弃,在 SEND_NOT_READY 时等待 fw_ready 回调。
  • 远端状态码:JL_PRO_STATUS_CRC_ERR/ALL_DATA_CRC_ERR 表示帧 CRC 校验失败,UNKOWN_CMD 表示命令未注册,PARAM_ERR 表示负载参数非法,RESP_DATA_OVER_LIMIT 表示应答超长——调试时先区分是本地 JL_ERR 还是应答中的 JL_PRO_STATUS。
  • 应答超时:JL_PRO_CB.wait_resp_timeout 回调携带重试计数 counter,协议栈等待应答依赖 JL_set_cur_tick() 喂入的时间戳,应用层若未周期调用 JL_protocol_process(),超时检测与发送队列都会停滞。
  • MTU 边界:单包负载受 jl_mtu_send 限制,大块数据(文件传输、运动数据同步)必须走 JL_DATA_* 消息并配合 FILE_BLUK_TRANSFER 等命令分片;JL_packet_set_mtu 的返回值才是实际生效值,发送前应查询 JL_packet_get_tx_max_mtu()。
  • 内存与并发:协议栈使用静态/外部传入缓冲池(JL_RECIEVE_BUF_SIZE、JL_CMD_POOL_SIZE 等),rcsp_packet_need_buf_size() 可预估总量;#pragma pack(1) 保证结构体无填充,但要求所有负载解析代码同样按 1 字节对齐访问。协议处理为单线程主循环模型,回调内禁止长时间阻塞,否则将影响应答及时性。
  • 鉴权失败:未通过鉴权时受保护命令被协议栈拒绝,应用层应监听 auth_pass_callback 再开放业务能力;连接断开后调用 JL_rcsp_auth_reset() 复位鉴权状态,防止旧会话复用。
  • 通道切换:BLE/SPP 切换通过 JL_protocol_dev_switch 更换 JL_PRO_CB 回调组,切换期间发送队列内容由应用层负责语义一致性(如丢弃跨通道的半成品命令)。

性能与运维

  • 内存占用:默认配置下接收缓冲约 672 字节、命令池 512 字节、应答池 256 字节、等待应答池 256 字节(见 JL_RECIEVE_BUF_SIZE 等宏);uboot 加载器场景(JL_RCSP_UBOOT_LIB)会自动削减池大小以适配受限 RAM。
  • 主循环驱动:JL_protocol_process() 需在系统定时器/任务中周期调用;rcsp_send_list_is_empty() 可用于低功耗休眠判定(队列空且无待处理帧时可允许系统进入睡眠)。
  • 调试手段:打开 RCSP_DEBUG_EN 后 rcsp_printf_buf 可打印收发原始帧,便于对照协议文档定位组包错误;各 CPU 目录(cpu/br23/liba/、cpu/br25/liba/、cpu/bd19/liba/ 等)下的 rcsp_stack.a 必须与当前芯片匹配,混用会导致链接或运行异常。
  • OTA 与工具链:协议栈同时服务于 PC 端 USB Dongle 升级工具(sdk_tools/USB Dongle OTA升级工具/PC_DONGLE_RCSP_V0.0.1.rar),设备端升级处理见 rcsp_updata/ 目录,属本页相邻话题。

扩展点

  1. 自定义命令区 JL_OPCODE_CUSTOMER_USER(0xFF):厂商私有命令的唯一合法扩展入口,协议头文件明确禁止在既有枚举中插入新 OpCode,保证与 APP 端的协议版本兼容。
  2. JL_PRO_CB 回调集:应用层通过回调注入通道发送、命令接收、应答接收与超时策略,可借此实现自定义重发/流控逻辑而不改动协议栈。
  3. AI 平台扩展:_AI_platform + get_ai_platform() 支持图灵(TULING)与深兰(DEEPBRAIN)语音平台,新增平台只需扩展枚举与授权码分发逻辑。
  4. 属性扩展:COMMON_INFO_ATTR_* 已预留编号空间,新增设备状态项可仿照 ATTR_TYPE_* 增加属性码并在 SYS_INFO_GET/SET/AUTO_UPDATE 处理中注册。
  5. MTU 协商:JL_OPCODE_NOTIFY_MTU + JL_packet_set_mtu() 允许运行时与 APP 协商传输尺寸,适配不同 BLE 协议栈的 ATT MTU。

Related Links

  • JL_rcsp_api.h(鉴权与 AI 平台接口)
  • JL_rcsp_packet.h(数据包格式与内存池)
  • JL_rcsp_protocol.h(命令码/属性/回调/发送接口)
  • rcsp_bluetooth.c(应用层集成入口)
  • rcsp_updata/rcsp_user_update.c(RCSP OTA 升级)
  • rcsp_hid_inter.c(HID 透传)
  • rcsp_msg.h(RCSP 消息分发)
Next
低功耗蓝牙 Mesh 方案(llsync_mesh)