2 开发说明
2.1 认证库使用
JL_Auth_x.x.x-release.har --- RCSP认证库
主要应用场景:在RCSP命令交互之前进行认证,避免非目标设备与App进行RCSP命令通讯。
Important
只有设备端和App端LinkKey一致的设备才能认证成功。
App端设置LinkKey 方法
import { JLAuth } from 'rcsp';
JLAuth.setLinkKey( [0x06, 0x77, 0x5f, 0x87, 0x91, 0x8d, 0xd4, 0x23, 0x00, 0x5d, 0xf1, 0xd8, 0xcf, 0x0c, 0x14, 0x2b]);//数组长度必须是16
Warning
每次蓝牙连接只可以与设备进行一次认证,重复认证会导致认证失败。若设备端打开认证,小程序端未认证就与设备进行RCSP命令通讯(包含OTA),设备不会回应命令。若设备端不打开认证,则不需要进行认证流程。
//初始化认证
let auth = new Auth()
//设备回复数据callback
let bleDataCallback: BleDataCallback = {
onReceiveData(res: WechatMiniprogram.OnBLECharacteristicValueChangeCallbackResult) {
//数据传输给认证库
auth.handlerAuth(res.deviceId, res.value)
}
}
//认证结果监听
let authListener: AuthListener = {
//发送认证数据回调
onSendData: (deviceId: string, data: ArrayBuffer) => {
//调用发数接口
this._SendData(deviceId, new Uint8Array(data))
},
//认证成功回调
onAuthSuccess: () => {
//移除设备回复数据callback
BleDataHandler.removeCallbacks(bleDataCallback)
//通知RCSP_SDK连接成功
this.rcspOp.transmitDeviceStatus(new Device(device.deviceId), Connection.CONNECTION_CONNECTED)
},
//认证失败回调
onAuthFailed: () => {
//移除设备回复数据callback
BleDataHandler.removeCallbacks(bleDataCallback)
this.bleConnect.disconnect()
},
}
//添加设备回复数据callback
BleDataHandler.addCallbacks(bleDataCallback)
//开始认证
auth.startAuth(device.deviceId, authListener)
设备断开时,请结束认证。避免认证失败回调,调用RcspImpl初始化,出现RCSP初始化失败现象。
//结束认证
auth.stopAuth()
2.2 RCSP库使用
JL_RCSP_x.x.x-release.har --- RCSP协议库
RCSP命令架构图:

SDK初始化:
Note
rcspOp.setOnSendDataCallback
:蓝牙发送数据
rcspOp.transmitDeviceData
:蓝牙回复数据
import { JL_RCSP } from 'rcsp';
//初始化
let rcspOp = new JL_RCSP.RcspImpl();
//设置RCSP发送数据回调
rcspOp.setOnSendDataCallback({
sendDataToDevice: (device: JL_RCSP.BtDevice, data: Uint8Array): boolean => {
//TODO 调用发数接口
throw new Error('Function not implemented.');
}
})
//设备回复数据callback
const bleDataCallback = {
onReceiveData(res) {
//数据传输给RCSP库
rcspOp.transmitDeviceData(new JL_RCSP.BtDevice(res.deviceId), new Uint8Array(res.value))
}
}
//添加设备回复数据callback
BleDataHandler.addCallbacks(bleDataCallback)
//RCSP事件回调
const onRcspCallback: JL_RCSP.OnRcspCallback = {
/**
* Rcsp协议初始化回调
*
* @param _device 已连接设备
* @param _isInit 初始化结果
*/
onRcspInit: (_device: JL_RCSP.BtDevice | null, _isInit: boolean) => {
},
/**
* 设备主动发送的rcsp命令回调
*
* @param _device 已连接设备
* @param _command RCSP命令
*/
onRcspCommand: (_device: JL_RCSP.BtDevice | null, _command: JL_RCSP.Command) => {
},
/**
* 设备回复的rcsp命令回调
*
* @param _device 已连接设备
* @param _command RCSP命令
*/
onRcspResponse: (_device: JL_RCSP.BtDevice | null, _command: JL_RCSP.Command) => {
},
/**
* 设备主动发送的数据命令回调
*
* @param _device 已连接设备
* @param _dataCmd 数据命令
*/
onRcspDataCmd: (_device: JL_RCSP.BtDevice | null, _dataCmd: JL_RCSP.Command) => {
},
/**
* RCSP错误事件回调
*
* @param _device 设备对象
* @param _error 错误码 (参考{@link com.jieli.rcsp.data.constant.RcspError})
* @param _message 错误描述
*/
onRcspError: (_device: JL_RCSP.BtDevice | null, _error: number, _message: string) => {
},
/**
* 需要强制升级回调
*
* @param _device 需要强制升级的设备
*/
onMandatoryUpgrade: (_device: JL_RCSP.BtDevice | null) => {
},
/**
* 设备连接状态
*
* @param _device 蓝牙设备
* @param _status 连接状态
*/
onConnectStateChange: (_device: JL_RCSP.BtDevice | null, _status: JL_RCSP.ConnectState) => {
},
}
//添加RCSP事件回调
rcspOp.addOnRcspCallback(onRcspCallback)
如何传输设备的连接状态:
Important
当传输设备状态之后,SDK就会开始与设备进行RCSP协议初始化(获取设备相关信息等)。初始化结果从 OnRcspCallback.onRcspInit()
回调
Warning
打开认证时,先认证成功,再传输连接状态
//设备连接已连接(打开认证时,先认证成功,再传输连接状态)
rcspOp.transmitDeviceState(new JL_RCSP.BtDevice(result.deviceId), JL_RCSP.ConnectState.CONNECTION_CONNECTED)
//设备连接已断开
rcspOp.transmitDeviceState(new JL_RCSP.BtDevice(result.deviceId), JL_RCSP.ConnectState.CONNECTION_DISCONNECT)
如何发送命令给设备:
//创建一条命令(例如:获取固件特征信息)
let device: JL_RCSP.BtDevice | null = rcspOp.getUsingDevice();
//构建命令
const param = new JL_RCSP.ParamTargetInfo(0xffffffff, 2); //android平台:0,iOS:1,小程序:2
let command = new JL_RCSP.CmdGetTargetInfo(param);
//构建命令回复回调
const commandCallback: JL_RCSP.CommandCallback<JL_RCSP.CmdGetTargetInfo> = {
onCmdResponse(device: JL_RCSP.BtDevice, command: JL_RCSP.CmdGetTargetInfo) {
//命令状态是否成功
if (command.getStatus() != JL_RCSP.CommonRespParam.STATUS_SUCCESS) {
const code = JL_RCSP.RCSPErrorCode.ERR_RESPONSE_BAD_STATUS;
return
}
const response = command.getResponse()
//命令是否有回复
if (null == response) {
return;
}
//强制转换成对应的Response
const responseTargetInfo = response as JL_RCSP.ResponseTargetInfo
//获取命令回复解析后的属性(举例:设备的版本名称)
responseTargetInfo.versionName;
},
onError(device: JL_RCSP.BtDevice, code: number, message: string) {
//命令异常
}
}
//发送命令
if (device != null) {
//命令超时时间
const timeoutMs = JL_RCSP.RcspConstant.DEFAULT_SEND_CMD_TIMEOUT;
rcspOp.sendRCSPCommand(device, command, timeoutMs, commandCallback);
}
2.3 OTA库使用
JL_OTA_x.x.x-release.har --- OTA库
Note
OTA库的使用方式: 方式1:使用OTAWrapper类进行OTA,对OTA库进行进一层封装(处理Auth,回连设备,管理RcspImpl),方便使用。可以内部管理RcspImpl,也可以外部管理RcspImpl。(推荐使用) 方式2:使用JL_OTA.RcspOTAManager类进行OTA,对OTA流程使用RCSP命令进行交互。需实现处理设备的认证流程,回连流程,管理RcspImpl。 方式3:使用JL_OTA.OTAImpl类进行OTA,负责控制OTA流程。需自己处理命令。(不推荐使用)
2.3.1 使用OTAWrapper进行OTA
通常情况下,我们只需要通过使用OTAWrapper就可以完成OTA功能。不需要实现和使用OTA库的接口。
第一步:初始化OTAWrapper
//OTAWrapper 初始化
const otaWrapperOption: OTAWrapperOption = {
/**是否需要认证。 在上层已经认证过,就不需要认证。**/
isUseAuth: () => {
return this._BluetoothConfigure.isUseAuth
},
/**是否需要回连。 在上层进行回连,就不需要内部回连。**/
isInnerReconnect: () => {
return true
},
/**扫描设备--一定是BLE设备,目前BootLoader设备只有BLE类型**/
sanDevice: () => {
//todo 实现蓝牙扫描操作
},
/**连接设备--一定是BLE设备,目前BootLoader设备只有BLE类型**/
connectDevice: (device: BluetoothDevice) => {
//todo 实现蓝牙连接操作
},
/**断开设备**/
disconnectDevice: (device: BluetoothDevice) => {
//todo 实现蓝牙断开操作
},
/**发送数据(非必须实现),
* 必须实现的情况:
* - 1.内部创建并管理RCSPImpl, 即OTAWrapperOption.getRCSPImpl未实现
* - 2.需要进行认证, 即OTAWrapperOption.isUseAuth返回false
* **/
sendData: (device: BluetoothDevice, data: Uint8Array) => {
//todo 实现蓝牙发数操作
}
/**获取RCSPImpl(非必须实现)。
* - 上层管理RCSPImpl则需要实现,如使用jl-rcsp-op时需要实现。
* - 上层不管理RCSPImpl则不需要实现,由内部创建并管理RCSPImpl
* **/
//getRCSPImpl?(device: BluetoothDevice): RCSPProtocol.RcspImpl | undefined
}
this._OTAWrapper = new OTAWrapper(otaWrapperOption)
第二步:监听蓝牙连接状态并同步OTAWrapper
// 通知 OTAWrapper 蓝牙连接成功
this._OTAWrapper.onConnectStateSuccess(dev)
// 通知 OTAWrapper 蓝牙连接失败
this._OTAWrapper.onConnectStateFailed(dev)
// 通知 OTAWrapper 蓝牙连接断开
this._OTAWrapper.onConnectStateDisconnect(dev)
第三步:监听蓝牙扫描状态并同步OTAWrapper
// 通知 OTAWrapper 发现设备
this._OTAWrapper.onScanFound(devs)
// 通知 OTAWrapper 扫描设备停止
this._OTAWrapper.onSanDeviceStop()
第四步:监听蓝牙数据推送并同步OTAWrapper
// 通知 OTAWrapper 收到数据
this._OTAWrapper.onReceiveData(OTADevice(res.deviceId), res.value)
第五步:连接设备
连接设备时,会进行RCSP的认证和RCSP的初始化。当认证失败或者初始化失败时,SDK会主动断开设备(OTAWrapperOption.disconnectDevice)。
若需要监听设备的初始化状态。可在OTAWrapper注册RCSP回调(OTAWrapper.registerRcspCallback)。
若需要判断设备是否初始化成功,可调用IOTAWrapper.isRCSPInit方法。
第六步:开始OTA
/*--- 开始执行OTA升级 ---*/
//创建OTA配置项
const otaConfig: JL_OTA.OTAConfig = new JL_OTA.OTAConfig()
//是否支持新的回连方式
otaConfig.isSupportNewRebootWay = true
//升级目标设备
const device = connectedDevices[0]
const onUpgradeCallback: OnUpgradeCallback = {
onStartOTA: () => {
// 开始升级
},
onExecuteDisconnectDevice: (): void => {
/** 执行断开设备.
* Spp设备需实现断开设备,
* Ble设备不需要实现断开设备.
* */
},
onNeedReconnect: (reConnectMsg: JL_OTA.ReconnectInfo, reconnectCallback: JL_OTA.OnResultCallback<string>) => {
// 正在回连
/** note: 如果需要使用自定义回连方式,请在此处实现。
* 连接成功时,调用 reconnectCallback.onResult(device.deviceId);通知SDK 设备的新的deviceId。
* **/
},
onProgress: (type: JL_OTA.UpgradeType, progress: number) => {
// 升级进度回调
if (type == JL_OTA.UpgradeType.UPGRADE_TYPE_CHECK_FILE) {
// 校验文件(传输BootLoader)
} else if (type == JL_OTA.UpgradeType.UPGRADE_TYPE_FIRMWARE) {
// 传输升级内容
}
},
onStopOTA: () => {
// 升级结束
},
onCancelOTA: () => {
// 升级取消
},
onError: (error: number, message: string) => {
// 升级失败
},
onReadData: (offset: number, size: number): Uint8Array | undefined => {
//读取升级文件的数据
},
onRCSPInit: (deviceId: string, isInit: boolean) => {
//回调通知-RCSP初始化结果
}
}
this._OTAWrapper.startOTA(device, otaConfig, onUpgradeCallback)
关于如何获取设备的固件版本信息:
Important
OTAWrapper.getDeviceInfo()
),设备信息中包含了固件的版本信息( deviceInfo.versionName
和 deviceInfo.versionCode
)2.4 单备份升级注意事项
关于单备份的强制升级有以下几点注意事项:
Important
关于单备份如何检查设备是否需要强制升级:
Important
RcspOpImpl.transmitDeviceStatus()
)。当OnRcspCallback 回调初始化成功后( OnRcspCallback.onRcspInit()
),上层可获取设备信息( RcspOpImpl.getDeviceInfo()
),设备信息中包含了是否需要强制升级( deviceInfo.mandatoryUpgradeFlag==1
)RcspOpImpl.transmitDeviceStatus()
)。当OnRcspCallback 回调需要强制升级时( OnRcspCallback.onMandatoryUpgrade()
) ,则表示该设备需要强制升级。不需要强制升级的设备是不会回调的。2.5 单备份升级的新回连广播包
该功能可选用:在设备端或小程序端之一选择不使用新回连,设备就会使用旧的广播包。小程序端配置 OTAConfig.isSupportNewRebootWay
部分设备和部分手机单备份升级时,在回连过程中,系统会直接回连上设备,导致SDK回连设备超时。故此在切换到Loader系统时,设备换了一个新的蓝牙地址,App端通过设备的广播包去判断设备是不是当前升级设备。
新回连广播包格式:
Byte0-4 |
Byte5 |
Byte6-11 |
Byte12-13 |
Byte14-15 |
Byte16 |
Byte17 |
Byte18-26 |
---|---|---|---|---|---|---|---|
JLOTA(标识) |
0 |
原BLE地址 |
|||||
JLOTA(标识) |
1 |
原BLE地址 |
UID |
PID |
Bit7-4:Type Bit3-0:Version |
电量 |
保留位 |
2.6 注意事项
为了防止单备份升级失败导致固件变”砖”, 因此固件单备份升级失败后会进入强制升级模式
因为未连接设备时, 不知道设备状态, 所以库初始化成功后需要查询设备升级状态
当连接上设备(若打开认证,需要先认证成功)后,可以将设备连接状态传输给RcspOpImpl
用户SDK或APP应该具备回连上一次连接的蓝牙设备的功能, 用于强制升级时自动回连设备, 再通过OTA升级更新固件
单备份方案,下载boot完成后,会先断开已连接的蓝牙(SPP或BLE), 进入uboot后,然后回连BLE
双备份方案, 不需要回连过程,直接开始升级流程
2.7 时序图
时序图仅作参考,具体细节以代码实际为准。
2.7.1 RCSP初始化时序
RCSP初始化时序图
2.7.2 RCSP OTA单备份升级时序
RCSP OTA单备份升级时序时序图
2.7.3 RCSP OTA双备份备份升级时序
RCSP OTA单备份升级时序时序图