RCSP协议与数据通道
RCSP(Remote Control Serial Port Protocol,杰理自定义遥控串口协议)是杰理(Jieli)蓝牙设备与手机 App 之间进行业务数据交互的核心协议。本文档基于 Android-JL_Bluetooth 仓库中的 PiHome(btsmart)示例应用,梳理 RCSP 协议在应用侧的接入方式、数据通道的建立过程、事件回调机制与相关配置。
Purpose and Scope
本文档覆盖以下内容:
- RCSP 协议在应用层的接入入口:
RCSPController的初始化与全局配置(BluetoothOption) - 数据通道的建立方式:BLE / SPP 传输层的优先级、MTU、多设备、设备鉴权等关键配置
- 事件回调机制:
BTRcspEventCallback的注册与分发,以及 btsmart 中tool.bluetooth.rcsp包下的任务类 - 连接状态查询与设备信息获取的典型用法(
LogService) - 协议运行时的数据流、失败模式与操作注意点
需要说明的是,com.jieli.bluetooth.impl.rcsp.RCSPController、BluetoothOption 等类来自杰理蓝牙 SDK(以 AAR 库依赖形式提供),其内部实现不在本仓库中;本仓库包含的是 SDK 的应用侧集成代码。因此本文档以仓库中可验证的调用代码为证据,描述协议通道的架构与接入方式,而不虚构 SDK 内部实现细节。
与本文档相关的兄弟页面(按目录推测):设备连接管理、扫描流程、OTA 升级、设备信息管理、日志上传等能力分别在各自的目录页中说明;本文档只聚焦 RCSP 协议与底层数据通道本身。
Overview
什么是 RCSP
RCSP 是杰理为自家蓝牙 SoC(耳机、音箱、车载、穿戴等设备)设计的私有应用层协议。它定义了一套"命令/响应"式的报文格式,运行在蓝牙经典(SPP)或低功耗蓝牙(BLE GATT)之上,用于承载诸如:
- 设备信息读取(电量、固件版本、设备名称等)
- 功能设置(EQ、按键、闹钟、FM 等)
- 文件系统操作(音乐列表、录音、OTA 固件传输)
- 事件上报(连接/断开、设备状态变化)
App 侧通过 SDK 提供的 RCSPController 单例与设备建立数据通道,并将上层业务命令封装为 RCSP 报文发送;设备侧回复的报文经 SDK 解析后,再以回调事件的形式分发给应用。
本仓库中的角色
在 PiHome(btsmart)示例中,RCSP 相关的应用侧代码分布在:
MainApplication.initSDK():SDK 与 RCSP 控制器的初始化、配置、回调注册(MainApplication.java)com.jieli.btsmart.tool.bluetooth.rcsp包:RcspEventHandleTask、ScanBleDeviceTask、UploadDeviceInfoTask等协议事件处理任务LogService:通过RCSPController查询连接状态与设备信息(LogService.java)
这些调用点共同构成了"App 业务层 → RCSP 协议层 → 蓝牙传输层 → 设备"的完整数据通道。
Architecture
flowchart TD
subgraph sg_App["应用层(btsmart 示例)"]
MainApp["MainApplication.initSDK()"]
Tasks["rcsp 任务包<br/>RcspEventHandleTask / ScanBleDeviceTask / UploadDeviceInfoTask"]
CacheMgr["ProductCacheManager / BleScanMsgCacheManager"]
LogSvc["LogService"]
end
subgraph sg_SDK["SDK 层(com.jieli.bluetooth,库依赖)"]
RCSP["RCSPController"]
Opts["BluetoothOption"]
Auth["设备鉴权 DeviceAuth"]
Transport["蓝牙传输通道<br/>BLE GATT / SPP"]
end
subgraph sg_Dev["设备端"]
Dev["杰理蓝牙设备<br/>(耳机/音箱等 SoC)"]
end
MainApp -->|"init() + 配置 BluetoothOption"| RCSP
RCSP -->|"addBTRcspEventCallback 注册"| CacheMgr
RCSP -->|"addBTRcspEventCallback 注册"| Tasks
Tasks -->|"业务处理/UI 通知"| LogSvc
RCSP -->|"解析配置"| Opts
Opts -->|"多设备/优先级/MTU/鉴权/扫描"| Transport
RCSP -->|"封装并收发 RCSP 报文"| Transport
Transport <-->|"BLE GATT 特征值 / SPP 串口"| Dev
架构说明:
- 应用层通过
RCSPController单例与 SDK 交互:初始化时注入BluetoothOption决定数据通道行为(是否多设备、是否优先 BLE、MTU 大小、是否鉴权、扫描模式),随后注册多个BTRcspEventCallback监听协议事件。 - SDK 层的
RCSPController负责 RCSP 报文的封装、发送、接收与解析,并把设备事件(连接/断开/命令响应)回调给应用层注册的监听器。该层同时管理底层蓝牙传输通道(BLE/SPP)的生命周期。 - 传输层通过 BLE GATT 特征值写入或经典蓝牙 SPP 与设备交换数据,RCSP 报文即承载于这些字节流之上。
- 设备端运行杰理固件,响应 RCSP 命令并主动上报事件。
这种分层设计的意图是:业务代码只面对协议级 API(连接状态、设备信息、命令回调),完全不接触蓝牙底层的 GATT/SPP 细节,从而让不同设备(BLE 或经典蓝牙)的差异被 SDK 屏蔽。
主要实现分析
RCSPController 的初始化与数据通道配置
RCSP 协议栈的入口是 RCSPController。在 PiHome 示例中,MainApplication.initSDK() 负责完成初始化(MainApplication.java):
//init rcsp wrapper
if (!RCSPController.isInit()) {
//config RCSPController
BluetoothOption bluetoothOption = BluetoothOption.createDefaultOption()
.setUseMultiDevice(true)
.setPriority(BluetoothOption.PREFER_BLE)
.setMandatoryUseBLE(SConstant.IS_USE_BLE_WAY)
.setMtu(BluetoothConstant.BLE_MTU_MAX)
.setUseDeviceAuth(PreferencesHelper.getSharedPreferences(MainApplication.getApplication())
.getBoolean(SConstant.KEY_USE_DEVICE_AUTH, SConstant.IS_USE_DEVICE_AUTH))
.setBleScanMode(2);
RCSPController.init(this, bluetoothOption);
}
设计要点(WHY):
RCSPController.isInit()守卫:保证整个进程生命周期内 SDK 只初始化一次,避免重复初始化导致状态错乱;后续所有模块通过getInstance()获取同一单例,共享同一条数据通道。BluetoothOption建造者模式:把数据通道的所有策略集中在一个配置对象中,初始化时一次性注入。setUseMultiDevice(true)开启多设备能力(PiHome 支持双设备),setPriority(PREFER_BLE)让连接策略优先走 BLE 通道,setMandatoryUseBLE(...)则进一步强制只走 BLE(由SConstant.IS_USE_BLE_WAY控制,可运行时切换)。setMtu(BluetoothConstant.BLE_MTU_MAX):BLE 数据通道的最大传输单元。MTU 决定单包可承载的 RCSP 报文长度,直接影响大命令(如文件传输、OTA)的分包行为;使用最大 MTU 可减少分包次数、提升吞吐。setUseDeviceAuth(...):是否启用设备鉴权,值来自 SharedPreferences(默认SConstant.IS_USE_DEVICE_AUTH)。鉴权用于校验设备合法性,是 RCSP 通道安全性的第一道门。setBleScanMode(2):指定 BLE 扫描模式,影响发现设备的速度与功耗。
BTRcspEventCallback 事件回调机制
初始化完成后,应用向控制器注册多个协议事件监听器(MainApplication.java):
RCSPController controller = RCSPController.getInstance();
controller.addBTRcspEventCallback(ProductCacheManager.getInstance());
controller.addBTRcspEventCallback(new RcspEventHandleTask(controller));
controller.addBTRcspEventCallback(new ScanBleDeviceTask(this, controller));
controller.addBTRcspEventCallback(new UploadDeviceInfoTask());
controller.addBTRcspEventCallback(BleScanMsgCacheManager.getInstance());
设计意图:
- 观察者模式:
RCSPController是事件源,BTRcspEventCallback是观察者接口;SDK 在收到设备连接、断开、命令响应等事件后广播给所有已注册的回调。这种一对多的分发让"协议事件"与"业务处理"解耦:缓存管理、扫描任务、日志上传互不干扰地各自消费事件。 - 职责分离的任务类:
RcspEventHandleTask(controller):持有控制器引用,作为协议事件的主处理任务,负责将底层事件转化为业务动作;ScanBleDeviceTask(this, controller):负责 BLE 扫描相关的协议交互(扫描参数、扫描结果处理);UploadDeviceInfoTask():无参构造,负责将设备信息/应用信息上传到服务器(见LogService中的ACTION_UPLOAD_DEVICE_MSG);ProductCacheManager、BleScanMsgCacheManager:单例缓存类,一边作为回调监听事件,一边为 UI 提供数据缓存。
连接状态与设备信息的查询入口
LogService 展示了运行时通过 RCSPController 查询数据通道状态的典型用法(LogService.java):
if (!RCSPController.isInit()) return START_STICKY;
final RCSPController rcspController = RCSPController.getInstance();
if (rcspController.isDeviceConnected()) {
DeviceInfo deviceInfo = rcspController.getDeviceInfo();
// ... 使用设备信息
}
这里的两个关键方法:
isDeviceConnected():同步查询当前数据通道是否已与设备建立连接;getDeviceInfo():返回已连接设备的DeviceInfo对象(电量、固件版本、设备名称等由 SDK 从 RCSP 响应中解析)。
同时注意 LogService 的守护逻辑:RCSPController.isInit() 为 false 时直接返回 START_STICKY,说明所有依赖 RCSP 的服务都必须先确认 SDK 已初始化,否则无法安全调用。
数据通道的组成
RCSP 数据通道可抽象为三层栈:
- 协议帧层:RCSP 命令/响应报文(由 SDK 封装,业务侧不直接接触字节);
- 传输适配层:根据
BluetoothOption选择 BLE GATT 或 SPP 作为载体,处理 MTU 分包、重传与鉴权握手; - 物理链路层:Android 蓝牙栈与设备的实际连接。
仓库中可见的证据是:BluetoothOption.PREFER_BLE、BLE_MTU_MAX、IS_USE_BLE_WAY 等常量共同决定了通道的传输选择,而设备端(杰理 SoC)是 RCSP 报文的最终对端。
核心流程:从初始化到数据交互
sequenceDiagram
participant App as MainApplication
participant RC as RCSPController
participant BT as 蓝牙传输层(BLE/SPP)
participant Dev as 杰理设备
App->>App: initSDK():准备日志/网络/数据库
App->>RC: isInit() == false → init(context, BluetoothOption)
Note over RC: 保存多设备/优先级/MTU/鉴权配置
App->>RC: addBTRcspEventCallback(多个监听器)
App->>RC: 发起设备扫描/连接(ScanBleDeviceTask)
RC->>BT: 按 PREFER_BLE 建立 BLE GATT 连接
BT->>Dev: 协商 MTU / 设备鉴权握手
Dev-->>BT: 鉴权通过,通道就绪
BT-->>RC: 连接成功通知
RC-->>App: 广播连接事件(所有 BTRcspEventCallback)
App->>RC: 发送业务命令(如 getDeviceInfo)
RC->>BT: 封装 RCSP 请求帧并按 MTU 分包
BT->>Dev: 写入 GATT 特征值 / SPP 数据
Dev-->>BT: 返回 RCSP 响应帧
BT-->>RC: 重组、解析报文
RC-->>App: 分发命令响应/设备信息
App->>App: RcspEventHandleTask 更新业务状态、缓存
流程说明:
- 初始化阶段:
MainApplication在应用启动时完成 SDK 初始化,通过BluetoothOption一次性固化数据通道策略;isInit()保证幂等。 - 注册阶段:多个
BTRcspEventCallback注册到控制器,形成事件广播总线。 - 建链阶段:
ScanBleDeviceTask驱动扫描与连接;传输层按配置优先走 BLE,连接后协商 MTU 并(可选)执行设备鉴权。 - 交互阶段:业务命令经
RCSPController封装为 RCSP 帧,按 MTU 分包后写入蓝牙通道;设备响应帧经接收、重组、解析后,以回调事件分发回各监听器。
用法示例
示例一:SDK 初始化与数据通道配置(应用启动)
//init rcsp wrapper
if (!RCSPController.isInit()) {
//config RCSPController
BluetoothOption bluetoothOption = BluetoothOption.createDefaultOption()
.setUseMultiDevice(true)
.setPriority(BluetoothOption.PREFER_BLE)
.setMandatoryUseBLE(SConstant.IS_USE_BLE_WAY)
.setMtu(BluetoothConstant.BLE_MTU_MAX)
.setUseDeviceAuth(PreferencesHelper.getSharedPreferences(MainApplication.getApplication())
.getBoolean(SConstant.KEY_USE_DEVICE_AUTH, SConstant.IS_USE_DEVICE_AUTH))
.setBleScanMode(2);
RCSPController.init(this, bluetoothOption);
}
示例二:注册协议事件回调(多监听器广播)
RCSPController controller = RCSPController.getInstance();
controller.addBTRcspEventCallback(ProductCacheManager.getInstance());
controller.addBTRcspEventCallback(new RcspEventHandleTask(controller));
controller.addBTRcspEventCallback(new ScanBleDeviceTask(this, controller));
controller.addBTRcspEventCallback(new UploadDeviceInfoTask());
controller.addBTRcspEventCallback(BleScanMsgCacheManager.getInstance());
示例三:后台服务中查询连接状态与设备信息
if (!RCSPController.isInit()) return START_STICKY;
final RCSPController rcspController = RCSPController.getInstance();
if (rcspController.isDeviceConnected()) {
DeviceInfo deviceInfo = rcspController.getDeviceInfo();
// ... 使用设备信息
}
三个示例覆盖了 RCSP 接入的完整生命周期:初始化配置 → 事件订阅 → 运行时查询,是任何基于该 SDK 的 App 必须遵循的接入顺序。
配置选项
数据通道行为由 BluetoothOption 统一配置,以下为仓库中可验证的配置项(MainApplication.java):
| 配置项 | 类型 | 示例值/默认值 | 说明 |
|---|---|---|---|
setUseMultiDevice | boolean | true | 是否支持多设备同时连接(PiHome 双设备场景需要) |
setPriority | int | BluetoothOption.PREFER_BLE | 连接优先级:优先 BLE 还是经典蓝牙 |
setMandatoryUseBLE | boolean | SConstant.IS_USE_BLE_WAY | 是否强制只使用 BLE 数据通道 |
setMtu | int | BluetoothConstant.BLE_MTU_MAX | BLE 最大传输单元,决定 RCSP 报文分包粒度 |
setUseDeviceAuth | boolean | SharedPreferences 存储,默认 SConstant.IS_USE_DEVICE_AUTH | 是否启用设备鉴权握手 |
setBleScanMode | int | 2 | BLE 扫描模式(功耗/速度权衡) |
其中 SConstant.IS_USE_BLE_WAY、SConstant.IS_USE_DEVICE_AUTH 等常量可从 SConstant.java 中按需修改,使同一套代码支持"纯 BLE"或"BLE+经典蓝牙"两种数据通道形态。
API 参考
以下为仓库中实际调用到的 RCSPController 公开 API(SDK 库依赖,签名以库内为准):
static boolean RCSPController.isInit()
判断 RCSP 协议栈是否已初始化。所有依赖 RCSP 的模块调用前应先检查。
返回: true 表示已初始化,可安全获取单例。
static void RCSPController.init(Context context, BluetoothOption option)
初始化 RCSP 协议栈并注入数据通道配置。应在 Application 启动阶段调用一次。
参数:
context(Context):应用上下文(MainApplication传入this)option(BluetoothOption):数据通道策略(多设备、优先级、MTU、鉴权、扫描模式)
抛出/约束: 需先经 isInit() 判断,避免重复初始化。
static RCSPController RCSPController.getInstance()
获取 RCSP 控制器单例,用于注册回调、查询状态、发送命令。
返回: 全局唯一的 RCSPController 实例。
void addBTRcspEventCallback(BTRcspEventCallback callback)
注册协议事件监听器。SDK 在设备连接、断开、命令响应等事件发生时广播给所有已注册回调。
参数:
callback(BTRcspEventCallback):事件监听器,如RcspEventHandleTask、ProductCacheManager等
boolean isDeviceConnected()
同步查询数据通道是否已与设备建立连接。
返回: true 表示连接中,可调用 getDeviceInfo()。
DeviceInfo getDeviceInfo()
获取已连接设备的设备信息(电量、固件版本等,由 SDK 解析 RCSP 响应得到)。
返回: DeviceInfo 对象;未连接时行为取决于 SDK 实现,调用前应先用 isDeviceConnected() 判断。
失败模式、边界情况与并发
未初始化访问
LogService 与 MainApplication 都显式检查 RCSPController.isInit()。若在初始化前调用 getInstance() 或发送命令,将导致空指针或协议栈异常——所有 RCSP 调用都必须以 isInit 为前置条件,这也是示例代码在服务中先判断再返回 START_STICKY 的原因。
设备鉴权失败
启用 setUseDeviceAuth(true) 后,连接阶段会执行鉴权握手。若设备未通过鉴权(固件不匹配、非杰理设备),数据通道将无法进入就绪状态,isDeviceConnected() 持续为 false,业务命令不会得到响应。鉴权开关与 SConstant.KEY_USE_DEVICE_AUTH 偏好设置联动,便于在设置页切换。
BLE 强制模式下的兼容性
setMandatoryUseBLE(true) 时只走 BLE 通道。对仅支持经典蓝牙(SPP)的旧设备,强制 BLE 会导致无法连接;反之,PREFER_BLE 只是优先级,可回退。选择何种通道形态取决于目标设备固件能力,示例通过 SConstant.IS_USE_BLE_WAY 常量集中控制。
MTU 与分包边界
RCSP 报文超过 MTU 时由 SDK 分包传输。若 setMtu 配置过小,大命令(OTA 固件、文件列表)会被切分成更多包,吞吐下降且失败概率上升;设备侧若未协商到期望 MTU,也需 SDK 侧回退处理。仓库使用 BluetoothConstant.BLE_MTU_MAX 取最大值,属于吞吐优先的策略。
并发与线程模型
RCSPController 为单例,事件回调由 SDK 内部线程分发;多个 BTRcspEventCallback 会顺序收到同一事件广播。业务侧在回调中应避免长时间阻塞(不要在回调线程执行 IO/网络),耗时操作应投递到自己的工作线程——例如 UploadDeviceInfoTask 这类上传任务不应在回调线程中同步执行。
多设备连接
setUseMultiDevice(true) 下,多个设备可能同时处于连接态,事件回调需要携带设备标识以区分来源。UI 层(如 DualDevAdapter)按设备维度展示状态,说明数据通道支持按设备隔离的协议会话。
性能与运维注意点
- MTU 最大化:示例显式设置
BLE_MTU_MAX,减少大报文分包,是 BLE 通道吞吐优化的关键手段。 - 扫描模式:
setBleScanMode(2)在发现速度与功耗间取平衡;量产场景可结合设备广播策略调整。 - 日志与可观测性:
JL_HttpClient、Logcat与LogService配合,可将连接状态、设备信息、协议日志上报,便于线上排查 RCSP 通道问题。 - 初始化顺序:
initSDK()中先初始化 HTTP/网络/数据库,再初始化 RCSP——确保事件回调(如UploadDeviceInfoTask)触发时依赖的组件已就绪。
扩展点
- 新增协议事件处理:实现
BTRcspEventCallback并调用addBTRcspEventCallback()注册,即可在不改动 SDK 与既有任务类的前提下扩展对新命令/新事件的响应,示例中的五个监听器即是该模式的实例。 - 切换数据通道形态:通过
SConstant.IS_USE_BLE_WAY、KEY_USE_DEVICE_AUTH等常量/偏好设置,可运行时调整通道策略,无需改动调用代码。 - 替换业务任务实现:
RcspEventHandleTask、ScanBleDeviceTask等均在tool.bluetooth.rcsp包内,属于应用侧可替换的实现;保持回调接口不变即可替换或新增任务。
测试与验证
仓库未包含针对 RCSP 协议层的单元测试(SDK 为库依赖,协议解析逻辑在库内)。应用侧的验证方式以真机联调为主:通过 LogService 上传设备信息、UploadDeviceInfoTask 上报应用信息,以及 ProductCacheManager 缓存断言连接数据。接入新设备时建议按以下顺序验证:初始化日志 → 扫描到设备 → 鉴权通过 → isDeviceConnected() 为 true → getDeviceInfo() 返回非空 → 业务命令回调正常。
Related Links
- MainApplication.java(RCSP 初始化与回调注册)
- LogService.java(连接状态与设备信息查询)
- SConstant.java(通道形态/鉴权等开关常量)
- 设备扫描与连接管理:见对应目录页(ScanBleDeviceTask 所在模块)
- 设备信息管理与 OTA:见对应目录页(依赖本页所述数据通道)
- 日志上报服务:见 LogService 相关目录页