杰理 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 在传输层之上增加了:
- 数据包封装:以
0xFE 0xDC 0xBA起始标签 + 头部位域 + 长度 + 负载 + 结束标签0xEF组成定界帧,解决字节流粘包/半包问题; - 命令/数据两类消息:
JL_CMD_*用于控制类命令,JL_DATA_*用于大块数据(如文件传输、运动数据),二者各自独立地支持"需要应答/无需应答"两种模式; - 设备鉴权:APP 首次连接须完成 link key 校验(
JL_rcsp_auth_init),未通过鉴权时协议栈拒绝大部分命令; - 属性化的信息模型:系统信息(电量、音量、设备句柄)、蓝牙音乐信息(标题、歌手、时长)、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;
关键设计点:
- 起始/结束标签:起始标签固定为
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); }
这些宏被协议栈内部用于解析/组装负载字段,应用层在构造自定义命令负载时也应复用它们,以保证与协议栈的字节序策略一致。
协议层:命令码与属性体系
命令码(OpCode)
命令码定义于 JL_rcsp_protocol.h,头文件注释特别强调该枚举不可插入新值(协议兼容性约束),扩展请使用保留区 JL_OPCODE_CUSTOMER_USER = 0xFF。主要命令分类如下:
| 命令码 | 值 | 用途 |
|---|---|---|
JL_OPCODE_DATA | 0x01 | 通用数据通道 |
JL_OPCODE_GET_TARGET_FEATURE_MAP / _FEATURE | 0x02 / 0x03 | 查询目标特性位图/特性 |
JL_OPCODE_DISCONNECT_EDR | 0x06 | 断开经典蓝牙(EDR)连接 |
JL_OPCODE_SYS_INFO_GET / _SET / _AUTO_UPDATE | 0x07 / 0x08 / 0x09 | 系统信息读/写/主动上报 |
JL_OPCODE_CALL_REQUEST | 0x0A | 通话请求 |
JL_OPCODE_SWITCH_DEVICE | 0x0B | 切换设备 |
JL_OPCODE_FILE_BROWSE_REQUEST_START / _STOP | 0x0C / 0x0D | 文件浏览启停 |
JL_OPCODE_FUNCTION_CMD | 0x0E | 功能命令(音乐/线控等) |
JL_OPCODE_SYS_OPEN_BT_SCAN / _STOP_BT_SCAN | 0x12 / 0x14 | 开启/停止蓝牙扫描 |
JL_OPCODE_SYS_UPDATE_BT_STATUS | 0x13 | 更新蓝牙状态 |
JL_OPCODE_SYS_BT_CONNECT_SPEC | 0x15 | 连接指定蓝牙地址 |
JL_OPCODE_SYS_FIND_DEVICE | 0x19 | 查找设备 |
JL_OPCODE_EXTRA_FLASH_OPT | 0x1A | Flash 扩展操作 |
JL_OPCODE_FILE_TRANSFER_START / _END / _TRANSFER / _CANCEL | 0x1B–0x1E | 文件传输生命周期 |
JL_OPCODE_FILE_DELETE / _RENAME | 0x1F / 0x20 | 文件删除/重命名 |
JL_OPCODE_ACTION_PREPARE | 0x21 | APP 操作预处理 |
JL_OPCODE_DEVICE_FORMAT | 0x22 | 设备格式化 |
JL_OPCODE_ONE_FILE_DELETE / _TRANS_BACK | 0x23 / 0x24 | 删除/回传单个文件 |
JL_OPCODE_FILE_BLUK_TRANSFER | 0x26 | 批量大文件传输准备 |
JL_OPCODE_DEVICE_PARM_EXTRA | 0x27 | 设备操作参数扩展 |
JL_OPCODE_SIMPLE_FILE_TRANS | 0x28 | 简单文件传输 |
JL_OPCODE_SPORTS_DATA_INFO_* / SENSOR_* | 0xA0–0xA6 | 运动/传感器数据同步 |
JL_OPCODE_NOTIFY_MTU | 0xD1 | MTU 通知 |
JL_OPCODE_GET_MD5 | 0xD4 | 获取 MD5 |
JL_OPCODE_LOW_LATENCY_PARAM | 0xD5 | 低延迟参数 |
JL_OPCODE_CUSTOMER_USER | 0xFF | 客户自定义命令区 |
属性类型(AttrType)
系统信息类属性(JL_rcsp_protocol.h):
| 属性 | 值 | 含义 |
|---|---|---|
ATTR_TYPE_PROTOCOL_VERSION | 0 | 协议版本 |
ATTR_TYPE_SYS_INFO | 1 | 系统信息(电量/音量等) |
ATTR_TYPE_EDR_ADDR | 2 | 经典蓝牙地址 |
ATTR_TYPE_PLATFORM | 3 | AI 平台 |
ATTR_TYPE_FUNCTION_INFO | 4 | 功能位图 |
ATTR_TYPE_DEV_VERSION / SDK_TYPE / UBOOT_VERSION | 5/6/7 | 版本信息 |
ATTR_TYPE_DOUBLE_PARITION | 8 | 双分区标志 |
ATTR_TYPE_UPDATE_STATUS | 9 | 升级状态 |
ATTR_TYPE_DEV_VID_PID / AUTHKEY / PROCODE / MAX_MTU | 10–13 | 设备标识与能力 |
ATTR_TYPE_MD5_GAME_SUPPORT | 19 | MD5 游戏支持 |
通用信息属性(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_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;
回调分工:
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_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_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;
};
这些 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()
_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 / 1 | AI 平台使能:图灵 / 深兰 |
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);
- 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); // 发送队列是否为空(休眠判定)
数据包接口(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_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/目录,属本页相邻话题。
扩展点
- 自定义命令区
JL_OPCODE_CUSTOMER_USER(0xFF):厂商私有命令的唯一合法扩展入口,协议头文件明确禁止在既有枚举中插入新 OpCode,保证与 APP 端的协议版本兼容。 JL_PRO_CB回调集:应用层通过回调注入通道发送、命令接收、应答接收与超时策略,可借此实现自定义重发/流控逻辑而不改动协议栈。- AI 平台扩展:
_AI_platform+get_ai_platform()支持图灵(TULING)与深兰(DEEPBRAIN)语音平台,新增平台只需扩展枚举与授权码分发逻辑。 - 属性扩展:
COMMON_INFO_ATTR_*已预留编号空间,新增设备状态项可仿照ATTR_TYPE_*增加属性码并在SYS_INFO_GET/SET/AUTO_UPDATE处理中注册。 - MTU 协商:
JL_OPCODE_NOTIFY_MTU+JL_packet_set_mtu()允许运行时与 APP 协商传输尺寸,适配不同 BLE 协议栈的 ATT MTU。