杰理 SDK 文档中心
首页
首页
  • 项目概览与入门

    • 项目概述
    • 快速开始
  • OTA SDK 核心库

    • RCSP 认证库(jl_auth)
    • OTA 流程库(jl_ota)
    • RCSP-OTA 协议库(jl_rcsp_ota)
    • OTAWrapper 高层封装
  • 蓝牙通信与设备管理

    • 蓝牙连接生命周期管理
    • BLE 数据发送与 MTU 管理
    • 自动回连机制
  • 参考 Demo 小程序

    • 应用入口与页面导航
    • 设备连接页(pageConnect)
    • 固件升级页(pageUpdate)
    • 设置与调试页(pageSetting)
    • 自定义 UI 组件
    • 固件文件解析工具(upgradeFileUtil)
    • 日志系统

BLE 数据发送与 MTU 管理

本文档深入解析 JLOTA 微信小程序固件升级 SDK 中 BLE 数据发送链路与 MTU(最大传输单元)管理的完整实现,涵盖 RCSP 数据包封帧、串行发送队列、响应超时重试、粘包解析,以及 sendMtu/receiveMtu 的协商与存储机制。

Purpose and Scope

本页面属于“BLE 数据链路”能力域,覆盖以下内容:

  • RCSP 协议数据包的封帧与解帧(包头 FE DC BA、标志位、opcode、长度、包尾 EF)
  • RCSPDataHandler 串行发送机制:发送队列、等待响应缓存、超时重试(最多 3 次)、接收解析队列
  • MTU 管理:DeviceInfoManager 中 per-device 的 sendMtu/receiveMtu 存储、默认协议 MTU(530)、CMD_SETTINGS_COMMUNICATION_MTU(0xD1)协商流程、OTA 流程中的 changeReceiveMtu()
  • SDK 与上层传输的边界:setOnSendDataCallback / sendDataToDevice 抽象,以及认证(Auth)流程如何复用该发送通道

以下内容不在本页面范围内,由其他目录页覆盖:

  • 设备扫描、连接与特征值订阅(小程序 BLE 适配层)
  • OTA 升级状态机(OTAImpl 的 start/cancel/progress/reconnect 流程)—— 仅在本页说明其与数据通道的交互点
  • 认证加密算法(jl_auth_2.0.0.js 中的密码学实现)

说明:仓库中的 SDK 为压缩混淆后的单行文件(jl_rcsp_ota_2.1.1.js 等),本页面基于其导出的类与方法语义进行解读;源码中未包含应用层 wx.writeBLECharacteristicValue 的具体适配实现,该部分以 SDK 暴露的 onSendData 回调为边界如实说明。

Overview

在微信小程序 BLE 场景下,小程序与杰理(Jieli)音频设备通过 GATT 特征值交换数据。为了让升级包、认证握手、设备控制命令稳定可靠地通过 BLE 传输,SDK 在 GATT 之上实现了一层 RCSP 应用协议:

  • 封帧:所有业务数据(命令 + 参数 / 响应)被封装为带固定头尾的 RCSP 包,便于接收端从字节流中切分帧。
  • 串行化:BLE 写操作必须逐个进行,SDK 用发送队列保证同一时刻只发送一个包,避免并发写导致丢包。
  • 可靠传输:需要响应的命令在发出后登记到"待响应缓存",启动超时定时器;超时后自动重发(上限 3 次),仍无响应则回调 ERROR_RESPONSE_TIMEOUT。
  • 粘包处理:BLE Notify 可能一次性带回多个包或半个包,RcspParser 负责从字节流中按 MTU 上限扫描合法包头,缓存不完整尾部。
  • MTU 语义:SDK 中 receiveMtu 表示"设备能接收的最大包长"(决定本端发送上限),sendMtu 表示"设备发送的最大包长"(决定本端解析上限)。二者由设备在连接初始化时上报(ResponseTargetInfo type 13),也可通过 CMD_SETTINGS_COMMUNICATION_MTU 动态协商。

这套设计的目标是:把不可靠、无流控的 BLE 传输抽象成类似串口的可靠命令通道,让上层(OTA、Auth、RCSP 业务命令)只关心业务语义,不必处理分帧、重传与背压。

Architecture

下图展示了 BLE 数据发送与 MTU 管理在 SDK 内的分层结构:

flowchart TD
    subgraph sg_App["应用层 (Mini Program)"]
        App["页面 / 业务代码"]
        IOAdapter["onSendData 回调<br/>(wx.writeBLECharacteristicValue 适配)"]
    end

    subgraph sg_SDK["RCSP 协议层 (jl_rcsp_ota_2.1.1.js)"]
        RcspImpl["RcspImpl (Ut)"]
        SNGen["CmdSnGenerator<br/>命令序号 0-255"]
        DataHandler["RCSPDataHandler (R)"]
        SendQueue["发送队列 H[]"]
        RecvQueue["接收解析队列 F[]"]
        PendingCache["待响应缓存 N[]"]
        TimeoutMap["超时定时器 Map G"]
        Parser["RcspParser (k)"]
        MtuMgr["DeviceInfoManager (At)"]
    end

    subgraph sg_Proto["协议/设备模型"]
        Packet["RcspPacket 封帧<br/>FE DC BA + flags + opcode + len + EF"]
        DevInfo["DeviceInfo<br/>sendMtu / receiveMtu"]
    end

    subgraph sg_Consumers["SDK 消费者"]
        OTA["OTAImpl (jl_ota_2.1.1.js)"]
        Auth["Auth (jl_auth_2.0.0.js)"]
    end

    App --> OTA
    App --> Auth
    OTA -->|"sendRCSPCommand / receiveFileBlock"| RcspImpl
    Auth -->|"onSendData(deviceId, data)"| IOAdapter
    RcspImpl --> SNGen
    RcspImpl --> DataHandler
    DataHandler --> SendQueue
    DataHandler --> PendingCache
    DataHandler --> TimeoutMap
    DataHandler --> RecvQueue
    DataHandler --> Parser
    DataHandler --> MtuMgr
    Parser --> Packet
    MtuMgr --> DevInfo
    DataHandler -->|"sendDataToDevice (IO 代理)"| IOAdapter
    IOAdapter -->|"BLE 写特征值"| App

各组件职责:

组件类/对象职责
RcspImplUt(导出为 RcspImpl)RCSP 操作门面:维护当前设备、命令序号生成、回调分发;sendRCSPCommand() 入队发送,transmitDeviceData() 入队解析
RCSPDataHandlerR核心数据通道:串行发送队列、待响应缓存、超时重发、接收解析队列;发送上限取 getReceiveMtu(),解析上限取 getSendMtu()
RcspParserk从接收字节流中按包头/包尾/长度切分 RCSP 帧,支持粘包与半包缓存
DeviceInfoManagerAt按 deviceId 存储 DeviceInfo,提供 getReceiveMtu / getSendMtu
RcspPacketwRCSP 帧结构:[FE DC BA][flags][opcode][len_hi][len_lo][payload][EF]
IO 适配应用注入通过 setOnSendDataCallback 注入,sendDataToDevice(device, bytes) 内部调用 wx.writeBLECharacteristicValue

设计意图:RCSPDataHandler 是唯一的字节收发出口,无论 OTA 大块固件数据、Auth 认证包还是普通命令,都必须经过它的队列与 MTU 校验,从机制上保证了 BLE 链路上的串行写与长度安全;MTU 值统一收敛在 DeviceInfoManager,发送与解析两侧共享同一数据源,避免各模块自行假设 MTU 导致不一致。

核心实现:数据发送链路

1. 命令发送入口

上层所有命令最终都汇聚到 RcspImpl.sendRCSPCommand(device, command, timeoutMs, callback):

sendRCSPCommand(t, s, e, r) {
    if (!this.kt(t, r)) return;                       // 设备必须等于当前使用设备
    if (null == s) { /* ERROR_INVALID_PARAM */ return; }
    s.isCommand() && s.setSn(this.mCmdSnGenerator.getRcspCmdSeq(t)); // 分配 0-255 序号
    const n = new g(t, s, e, r);                      // 包装为 DataInfo(含 timeoutMs/callback)
    this.mRCSPDataHandler.W(n)                        // 入发送队列
}

Source: jl_rcsp_ota_2.1.1.js

要点:

  • 每个命令由 CmdSnGenerator 分配 0–255 的序号(按设备独立递增,(sn+1) % 256),用于匹配响应。
  • DataInfo(类 g)持有 command、timeoutMs、callback、重发计数 _ 与时间戳 O。
  • 发送前先做 kt() 校验:命令目标必须是当前 mTargetDevice,否则直接报 ERROR_DEVICE_OFFLINE。

2. RCSPDataHandler 串行发送与重试

发送入队(W)与处理(X)的关键逻辑:

W(t) { // 入队发送
    if (this.B(t)) {                                  // 校验非空 & 通道已启动
        if (this.H.push(t), this.H.length > 1)
            return void n("RCSPDataHandler: 放入数据缓冲区,等待发送");
        const s = { complete: () => { this.X(this.H, s) } };
        this.X(this.H, s)                             // 队列为空则立即处理
    }
}
X(t, s) { // 串行发送循环
    const e = t.shift();
    if (null == e) { /* ... */ }
    if (!this.Z(e)) return this.$(e, ERROR_IO_EXCEPTION, "send data failed."), ...;
    if (e.command.isNeedResponse()) {
        -1 == this.N.indexOf(e) && this.N.push(e);    // 登记待响应缓存
        let timer = setTimeout((t) => {
            // 超时:从缓存移除;重发计数 < 3 则重发,否则 ERROR_RESPONSE_TIMEOUT
            if (e._ < this.T) { e._ = e._ + 1; this.W(e) }
            else this.$(e, ERROR_RESPONSE_TIMEOUT, "Command[...]");
        }, e.timeoutMs, e);
        this.G.set(this.tt(e), timer);                // key = opcode<<16 | sn
    } else this.st(e);                                // 无需响应:直接回调 onCmdResponse
    s.success?.(), s.complete?.()
}

Source: jl_rcsp_ota_2.1.1.js

设计意图:

  • 队列即背压:H 队列保证"同一时刻只有一个包在写"。BLE 的 writeBLECharacteristicValue 是异步且无流控的,并发写会导致系统层失败或覆盖;串行化把速率控制交给"收到响应后再发下一个"的天然握手。
  • 超时即重发:N 缓存 + G 定时器构成 request-response 匹配。超时后先移除缓存再重发,避免重复响应被二次匹配。
  • 重发上限:T = 3(常量在 RCSPDataHandler 构造函数中)。超过上限回调 ERROR_RESPONSE_TIMEOUT(-64)并通知全局 listener.onError。

3. 发送前的封帧与长度校验

真正把字节交给 IO 层的是 Z(t):

Z(t) {
    const s = t.command.v();                          // 封帧:RcspPacket.v() 生成完整 RCSP 包
    if (null == s || 0 == s.byteLength) return false; // 数据为空
    if (s.byteLength > this.et(t.device))             // 超过设备 receiveMtu → 拒绝发送
        return h("RCSPDataHandler: sendData : data over limit. RCSP mtu = " + ...), false;
    let e = false;
    for (let r = 0; r < 3 && (e = this.ioProxy.sendDataToDevice(t.device, s), !e); r++);
    return e                                          // 系统写失败时立即重试 3 次
}
et(t) { // 发送长度上限 = 设备的 receiveMtu(设备能收多大)
    let s = this.deviceMtuManager.getReceiveMtu(t);
    return null != s && s > 0 ? s : p.DEFAULT_PROTOCOL_MTU  // 默认 530
}

Source: jl_rcsp_ota_2.1.1.js

RCSP 帧结构(RcspPacket.v() 生成,RcspPacket.l() 解析):

偏移内容说明
0–2FE DC BA固定包头 RCSP_HEAD
3flagsbit7=command(0x80),bit6=needResponse(0x40),bit0-5=reserve
4opcode命令码(如 CMD_SETTINGS_COMMUNICATION_MTU=0xD1、OTA 命令 0xE1–0xE8)
5–6lengthpayload 长度(大端 2 字节)
7..7+lenpayload命令参数或响应体
末尾EF固定包尾 RCSP_END

其中 command 包在 payload 首字节携带 SN(序号),响应包则在第 0 字节为 status、第 1 字节为 SN。

4. 接收链路:粘包解析与响应匹配

BLE Notify 数据到达后经 transmitDeviceData() 进入 RCSPDataHandler.K(),再交给 j() 解析:

j(t, s) { // 接收解析循环
    const e = t.shift();
    const r = this.V.rt(this.nt(e.device), e.data);   // 按 sendMtu 上限切分 RCSP 帧
    r.forEach((t) => {
        if (t.isCommand()) {                          // 设备发来的命令
            const s = this.V.t(t);
            null == s ? /* ERROR_NONE_PARSER */ : this.listener.onRcspCommand(e.device, s);
        } else {                                      // 设备发来的响应
            const s = this.it(this.N, t);             // 在待响应缓存中按 opcode+sn 匹配
            if (null == s) return;                    // 找不到对应命令(超时已移除)
            const r = this.tt(s), i = this.G.get(r);  // 清除超时定时器
            null != i && (clearTimeout(i), this.G.delete(r));
            const a = s.command;
            const r2 = a.getResponse().l(t.h());      // 解析响应体
            r2 >= 0 ? (this.listener.onRcspResponse(e.device, a), this.st(s))
                    : this.$(s, ERROR_DATA_FORMAT, ...);
        }
    });
}
nt(t) { // 接收解析上限 = 设备的 sendMtu(设备能发多大)
    let s = this.deviceMtuManager.getSendMtu(t);
    return null != s && s > 0 ? s : p.DEFAULT_PROTOCOL_MTU
}

Source: jl_rcsp_ota_2.1.1.js

RcspParser(类 k)的 rt(mtu, data) 实现"先合并半包缓存 → 扫描包头 → 校验长度 ≤ mtu 且包尾为 EF → 切帧",无法凑齐的尾部数据通过 wt() 缓存等待下一包;长度超过 MTU 的"脏帧"直接丢弃并继续向后扫描,体现了对非可靠传输的健壮性设计。

5. 发送-响应时序总览

sequenceDiagram
    participant App as 应用层
    participant Rcsp as RcspImpl
    participant H as RCSPDataHandler
    participant IO as onSendData 回调 (BLE 写)
    participant Dev as BLE 设备

    App->>Rcsp: sendRCSPCommand(cmd, timeout, cb)
    Rcsp->>Rcsp: 分配 SN (0-255)
    Rcsp->>H: W(DataInfo) 入队
    H->>H: Z(): 封帧 + 校验长度 <= receiveMtu
    H->>IO: sendDataToDevice(device, packet)
    IO->>Dev: wx.writeBLECharacteristicValue
    H->>H: 登记 N[] 缓存 + G 启动超时定时器
    Dev-->>IO: Notify 返回数据
    IO->>H: K(DataInfo) 入队
    H->>H: Parser 切帧 (上限 sendMtu)
    H->>H: 匹配 N[] (opcode+sn) → 清除定时器
    H->>Rcsp: onRcspResponse → 上层回调 onResult
    Note over H: 超时未响应 → 重发 (最多 3 次)<br/>仍无响应 → ERROR_RESPONSE_TIMEOUT

核心实现:MTU 管理

1. 默认值与存储

class p {}
p.DEFAULT_SEND_CMD_TIMEOUT = 3e3      // 默认命令超时 3000ms
p.DEFAULT_PROTOCOL_MTU   = 530        // 默认协议 MTU 530 字节

DeviceInfoManager(类 At)以 deviceId 为键维护 DeviceInfo,其中 sendMtu / receiveMtu 初始默认均为 DEFAULT_PROTOCOL_MTU(530),设备信息同步后由实际值覆盖:

class At extends U {
    constructor() { super(...arguments); this.deviceInfoMap = new Map }
    getReceiveMtu(t) { const s = this.getDeviceInfo(t); return null != s && s.receiveMtu > 0 ? s.receiveMtu : null }
    getSendMtu(t)    { const s = this.getDeviceInfo(t); return null != s && s.sendMtu > 0    ? s.sendMtu    : null }
    updateDeviceInfo(t, s) { this.deviceInfoMap.set(t.deviceId, s) }
}

Source: jl_rcsp_ota_2.1.1.js

方向性语义(务必区分):RCSPDataHandler.et()(发送上限)读的是 receiveMtu,nt()(接收解析上限)读的是 sendMtu。命名以"设备视角"为准:receiveMtu = 设备接收能力 = 手机可发送的最大包长;sendMtu = 设备发送能力 = 手机可接收的最大包长。

2. MTU 信息来源一:连接初始化同步

设备连接成功(Connection.CONNECTION_CONNECTED)后,RcspImpl.St() 调用 syncDeviceInfo() 下发 CmdGetTargetInfo,设备返回 ResponseTargetInfo。其中 type 13 字段携带 MTU:

case 13:
    s.length >= 4 ? (this.sendMtu = (255 & s[0]) << 8 | s[1],
                     this.receiveMtu = (255 & s[2]) << 8 | s[3])
                  : 2 == s.length && (this.sendMtu = (255 & s[0]) << 8 | s[1],
                                      this.receiveMtu = this.sendMtu)

Source: jl_rcsp_ota_2.1.1.js

3. MTU 信息来源二:动态协商(CMD 0xD1)

设备可通过 CMD_SETTINGS_COMMUNICATION_MTU(opcode 0xD1)主动上报/协商 MTU,RcspImpl.gt() 处理该命令:把参数中的 protocolMtu 写入当前设备的 receiveMtu 并回包(ResponseMtu.realProtocolMtu);响应返回后 At() 再用 realProtocolMtu 更新 receiveMtu。这使设备在固件升级等场景中能主动把接收窗口放大,让手机端发送更大的数据块。

4. OTA 场景的 MTU 抬升

在 jl_ota_2.1.1.js 的 OTA 状态机中,当设备 isNeedBootLoader 时,进入更新模式前会调用:

changeReceiveMtu() {
    if (!this.isDeviceConnected()) return;
    const e = this.Ut.getDeviceInfo(this._t);
    null != e && e.receiveMtu < t.RcspConstant.DEFAULT_PROTOCOL_MTU &&
        (e.receiveMtu = t.RcspConstant.DEFAULT_PROTOCOL_MTU,   // 抬升到 530
         this.Ut.getDeviceInfoManager().updateDeviceInfo(this._t, e))
}

Source: jl_ota_2.1.1.js

设计意图:OTA 固件传输是吞吐敏感路径,BootLoader 场景下设备侧接收能力通常受限;在发送固件块(receiveFileBlock)之前先强制把 receiveMtu 抬到 530,使每个 CmdReadFileBlock 能携带最大数据块,减少 BLE 包数量、缩短升级耗时。这是"以发送端 MTU 驱动升级速率"的典型工程取舍。

使用示例

注意:仓库内 SDK 文件为压缩单行源码,以下示例为从源码中提取的片段并做语义化排版,标识符保持原样。

示例一:注册 BLE 传输回调(SDK 与小程序传输层的边界)

RcspImpl 通过 setOnSendDataCallback 注入实际的 BLE 写实现。SDK 内所有数据(命令、OTA 固件块、认证包)最终都走这一出口:

// RcspImpl 内的转发逻辑
sendDataToDevice(t, s) {
    return null == this.mOnSendDataCallback
        ? (h("RcspImpl: OnSendDataCallback is null,so sendDataToDevice failed"), !1)
        : this.mOnSendDataCallback.sendDataToDevice(t, s)
}

Source: jl_rcsp_ota_2.1.1.js

应用层需要提供一个 { sendDataToDevice(device, arrayBuffer) } 对象,内部调用 wx.writeBLECharacteristicValue,并把 wx.onBLECharacteristicValueChange 收到的数据通过 transmitDeviceData(device, buffer) 回灌给 SDK。仓库中未包含该适配器的具体实现(源码缺失),接入时需在业务代码中补齐。

示例二:认证流程复用发送通道

jl_auth_2.0.0.js 的 Auth 类不直接写 BLE,而是回调应用注入的 onSendData,并配合 5 秒超时任务实现握手机制:

_writeAuthData(t) {
    this.authDeviceId && (this.callback?.onSendData(this.authDeviceId, t), this._startTimeoutTask())
}
_startTimeoutTask() {
    this.timeoutTaskId = setTimeout((() => { this._onAuthFailed(this.authDeviceId) }), 5e3)
}

Source: jl_auth_2.0.0.js

可见"发送 + 超时重试"是 SDK 各模块共用的通用模式:Auth 自行管理 5s 超时,RCSPDataHandler 管理命令级超时,二者共享同一个字节出口,但责任边界清晰。

示例三:字节与十六进制转换工具

util.js 提供 BLE 调试常用的转换函数(非压缩源码,可直接引用):

export function ab2hex(buffer) {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function (bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('')
}

export function hexToBytes(hex) {
	for (var bytes = [], c = 0; c < hex.length; c += 2)
		bytes.push(parseInt(hex.substr(c, 2), 16));
	return bytes;
}

Source: util.js

Configuration Options

SDK 内的"配置"以常量形式硬编码(无外部配置文件),列示如下:

常量值所属类说明
DEFAULT_PROTOCOL_MTU530RcspConstant (p)协议层默认 MTU;设备未上报或上报值非法时回退值
DEFAULT_SEND_CMD_TIMEOUT3000 msRcspConstant (p)syncDeviceInfo 等内部命令的默认超时
RCSPDataHandler.T3RCSPDataHandler (R)命令响应超时的最大重发次数
Auth._startTimeoutTask5000 msAuth认证握手单步超时
RCSP_HEAD / RCSP_END[254,220,186] / 239RcspPacket (w)帧头帧尾,切帧依据
Connection0/1/2exportsDISCONNECT / CONNECTING / CONNECTED 状态枚举

日志可通过 setLogger / setLogGrade(0–5,对应 verbose→error)注入与调节。

API Reference(关键接口)

RcspImpl.sendRCSPCommand(device, command, timeoutMs, callback)

  • 描述:发送一条 RCSP 命令。自动分配 SN、封装为 DataInfo 并进入 RCSPDataHandler 发送队列。
  • 参数:
    • device(Device):目标设备,必须等于 getUsingDevice(),否则报 ERROR_DEVICE_OFFLINE。
    • command(Command):命令对象(如 CmdGetTargetInfo、CmdReadFileBlock),isCommand() 为 true 时自动赋 SN。
    • timeoutMs(number):响应超时阈值。
    • callback({onResult, onError}):结果回调。
  • 回调:成功走 onCmdResponse → callback.onResult;失败走 onError(errorCode, desc)。

RCSPDataHandler.W(DataInfo) / K(DataInfo)

  • W:入发送队列;队列空则立即串行发送,非空则等待前序完成。
  • K:入接收解析队列;由 RcspParser 按 sendMtu 切帧后分发给 onRcspCommand / onRcspResponse。
  • 前置条件:通道已启动(L(),连接建立时调用);未启动时回调 ERROR_IO_EXCEPTION。

DeviceInfoManager.getReceiveMtu(device) / getSendMtu(device)

  • 返回设备上报的接收/发送 MTU;不存在或 ≤0 时返回 null,调用侧回退到 DEFAULT_PROTOCOL_MTU(530)。
  • 写入入口:syncDeviceInfo 结果(type 13)、CMD_SETTINGS_COMMUNICATION_MTU 命令与响应、OTA changeReceiveMtu()。

RcspParser.rt(sendMtu, data) → RcspPacket[]

  • 将原始字节流切分为完整 RCSP 帧数组;半包缓存进 ht,超长帧(长度 > sendMtu)丢弃并继续扫描。

Failure Modes, Edge Cases & Concurrency

失败模式与错误码

场景错误码触发点
发送包超过设备 receiveMtu发送直接失败(无错误码回调)Z() 中长度校验,随后 $() 报 ERROR_IO_EXCEPTION(-35)
命令超时且重发 3 次仍无响应ERROR_RESPONSE_TIMEOUT (-64)X() 中 G 定时器触发
响应体解析失败ERROR_DATA_FORMAT (-3)j() 中 getResponse().l() 返回值 < 0
收到无法识别的命令 opcodeERROR_NONE_PARSER (-67)j() 中 V.t(t) 返回 null
设备非当前使用设备/离线ERROR_DEVICE_OFFLINE (-33)kt() 校验
通道未启动(未连接)ERROR_IO_EXCEPTION (-35)B() 校验 M 标志
重复连接ERROR_REPEAT_STATUS (-36)vt() 中 CONNECTED 时已有 mTargetDevice

并发与一致性

  • 发送串行化:H 队列 + M 运行标志保证单写者;X() 每次只 shift() 一个包处理。
  • 响应匹配:N 缓存与 G 定时器以 opcode<<16 | sn 为键;同一命令重发后,旧定时器已被清除,不会出现双定时器。
  • 断线清理:J() 会遍历 N 回调 ERROR_IO_EXCEPTION、清空所有定时器与队列,防止断线后悬挂的 Promise/回调泄漏。
  • OTP 序号回绕:SN 按 256 取模递增,it() 按 opcode+sn 双条件匹配,短周期内同命令同序号的重叠由 minSameCmdE5Time(OTA 层 50ms 去重)缓解。

边界情况

  • 单包恰好等于 MTU 上限时允许发送(> 才拒绝)。
  • 半包(byteLength < 8)进入缓存;跨多帧粘包时循环切帧直到缓冲区耗尽。
  • 设备上报 MTU 为 0/非法时回退 530,保证老设备兼容。

Performance & Operational Considerations

  • 吞吐瓶颈在 MTU 与往返:每块 OTA 数据(CmdReadFileBlock)需等待设备 CmdReadFileOffset 请求-响应循环,实际速率 ≈ MTU / 往返时延;因此 changeReceiveMtu() 抬升到 530 是升级性能的关键开关。
  • 写失败即时重试:Z() 对 sendDataToDevice 失败最多立即重试 3 次(不占用命令级重发配额)。
  • 日志分级:setLogGrade(1..5) 控制 verbose→error;setLogger 可接小程序 console,用于线上排查 MTU 协商与超时问题。
  • 内存:发送/接收队列上限无显式限制,但受"单命令单响应"约束,正常并发数等于未完成命令数;大文件升级靠 receiveFileBlock 逐块推进,不会整包驻留。

Extension Points

  1. 传输层替换:setOnSendDataCallback({sendDataToDevice}) 是唯一字节出口,可替换为 SPP、USB 或其他通道实现,实现 OTAConfig.COMMUNICATION_WAY_*(0=BLE/1=SPP/2=USB)对应的多通道传输。
  2. 自定义命令:CmdCustom(0xF0)/ CmdExtraCustom(0xFF)允许业务方定义私有命令,自动享受队列、SN、超时重发与 MTU 校验。
  3. 监听回调:addOnRcspCallback(OnRcspCallback) 可注册多路监听器(如 OTA 与业务层共存),RcspCallbackManager 负责广播。
  4. MTU 协商扩展:设备侧可通过 CmdSetMtu 主动协商,应用侧无需改动即可感知(RcspImpl.gt() 自动更新 receiveMtu)。

Related Links

  • jl_rcsp_ota_2.1.1.js(RCSP 协议与数据通道实现)
  • jl_ota_2.1.1.js(OTA 升级状态机,消费数据通道)
  • jl_auth_2.0.0.js(认证握手,复用 onSendData 通道)
  • util.js(ab2hex / hexToBytes 等 BLE 调试工具)
  • 相关目录页:BLE 连接与特征值管理、OTA 升级流程、设备认证(见目录结构 3.x 章节)
Prev
蓝牙连接生命周期管理
Next
自动回连机制