2. 开发说明

2.1 认证库使用

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)

2.2 RCSP库使用

RCSP命令架构图:

../_images/RCSP命令架构图.png

Note

目前这个渠道的RCSP库只支持OTA命令

SDK初始化:

//初始化
let rcspOp = new RcspOpImpl();
//设置RCSP发送数据回调
rcspOp.setOnSendDataCallback({
  sendDataToDevice: (device: Device, data: Uint8Array): boolean => {
    //调用发数接口
    return this._SendData(device.mac, data)
  }
})
//设备回复数据callback
const bleDataCallback = {
  onReceiveData(res: WechatMiniprogram.OnBLECharacteristicValueChangeCallbackResult) {
    //数据传输给RCSP库
    rcspOp.transmitDeviceData(new Device(res.deviceId), new Uint8Array(res.value))
  }
}
//添加设备回复数据callback
BleDataHandler.addCallbacks(bleDataCallback)
//RCSP事件回调
const onRcspCallback: OnRcspCallback = {
    /**
    * Rcsp协议初始化回调
    *
    * @param device 已连接设备
    * @param isInit 初始化结果
    */
    onRcspInit(device?: Device | null, isInit?: boolean){},
    /**
    * 设备主动发送的rcsp命令回调
    *
    * @param device  已连接设备
    * @param command RCSP命令
    */
    onRcspCommand(device: Device | null, command: CommandBase){},
    /**
    * 设备主动发送的数据命令回调
    *
    * @param device  已连接设备
    * @param dataCmd 数据命令
    */
    onRcspDataCmd(device: Device | null, dataCmd: CommandBase){},
    /**
    * RCSP错误事件回调
    *
    * @param device  设备对象
    * @param error   错误码 (参考{@link com.jieli.rcsp.data.constant.ErrorCode})
    * @param message 错误描述
    */
    onRcspError(device: Device | null, error: number, message: string){},
    /**
    * 需要强制升级回调
    *
    * @param device 需要强制升级的设备
    */
    onMandatoryUpgrade(device: Device | null){},
    /**
    * 设备连接状态
    *
    * @param device 蓝牙设备
    * @param status 连接状态
    */
    onConnectStateChange(device: Device | null, status: Connection){}
  }
//添加RCSP事件回调
rcspOp.addOnRcspCallback(onRcspCallback)

如何传输设备的连接状态:

Important

当传输设备状态之后,SDK就会开始与设备进行RCSP协议初始化(获取设备相关信息等)。初始化结果从 OnRcspCallback.onRcspInit() 回调

Warning

打开认证时,先认证成功,再传输连接状态

//设备连接已连接(打开认证时,先认证成功,再传输连接状态)
this.rcspOp.transmitDeviceStatus(new Device(result.deviceId), Connection.CONNECTION_CONNECTED)


//设备连接已断开
this.rcspOp.transmitDeviceStatus(new Device(result.deviceId), Connection.CONNECTION_DISCONNECT)

如何发送命令给设备:

//创建一条命令(例如:获取固件特征信息)
let devcie: Device | null = this.rcspOp.getUsingDevice();
//构建命令
const param = new ParamTargetInfo(0xffffffff, 2);//android平台:0,iOS:1,小程序:2
let command = new CmdGetTargetInfo(param);
//构建命令回复回调
const commandCallback: CommandCallback ={
    onCmdResponse(device: Device, command: CommandBase) {
        //命令状态是否成功
        if (command.getStatus() != ResponseBase.STATUS_SUCCESS) {
            const code = ErrorCode.ERROR_REPLY_BAD_STATUS;
            return
        }
        const response = command.response
        //命令是否有回复
        if (null == response) {
            return;
        }
        //强制转换成对应的Response
        const responseTargetInfo = response as ResponseTargetInfo
        //获取命令回复解析后的属性(举例:设备的版本名称)
        responseTargetInfo.versionName;
    },
    onError(device: Device, code: number, message: string) {
        //命令异常
    }
}
//发送命令
if(device!=null){
    //命令超时时间
    const timeoutMs = RcspConstant.DEFAULT_SEND_CMD_TIMEOUT;
    this.rcspOp.sendRCSPCommand(device,command,timeoutMs,commandCallback);
}

2.3 OTA库使用

目前小程序的OTA_SDK只处理OTA流程的控制,没有做命令解析和构建的处理。所以在使用的时候需要通过 ota-rcsp.ts 与RCSP_SDK建立命令解析和命令构建的联系。

关于如何获取设备的固件版本信息:

Important

获取设备的固件版本信息,可用以下几种方式进行:
1.连接上设备后,传输连接状态给RCSP-SDK( RcspOpImpl.transmitDeviceStatus() )。当OnRcspCallback 回调初始化成功后( OnRcspCallback.onRcspInit() ),上层可获取设备信息( RcspOpImpl.getDeviceInfo() ),设备信息中包含了固件的版本信息( deviceInfo.versionNamedeviceInfo.versionCode )
2.自定义命令交互

2.3.1 OTA_SDK接口使用

使用 OTAImpl 之前,需要先实现 IOTAOp 接口,对OTA每个流程的数据进行处理( ota-rcsp.ts 已做了处理)。ota-rcsp中的 RcspOTAManager 已封装好了OTA_SDK的相关接口,可直接使用RcspOTAManager代替OTAImpl接口。

1.设备初始化(当RCSP库初始化成功后,单备份回连成功也需要调用)

OTAImpl接口

OTAImpl.onDeviceInit(deviceUpgradeInfo: DeviceUpgradeInfo | undefined, isInit: boolean | undefined)

RcspOTAManager 对应的接口(无),内部已处理

2.开始升级

OTAImpl接口

OTAImpl.startOTA(config: OTAConfig, callback: OnUpgradeCallback)

RcspOTAManager 对应的接口

RcspOTAManager.startOTA(config: OTAConfig, callback: OnUpgradeCallback)

3.取消升级(仅双备份有效)

OTAImpl接口

OTAImpl.cancelOTA()

RcspOTAManager 对应的接口

RcspOTAManager.cancelOTA()

4.状态同步,设备断开(正常单备份升级会断开设备进行回连)

OTAImpl接口

OTAImpl.onDeviceDisconnect()

RcspOTAManager 对应的接口(无),内部已处理

5.释放缓存

OTAImpl接口

OTAImpl.release()

RcspOTAManager 对应的接口

RcspOTAManager.release()

2.4 单备份升级注意事项

关于单备份的强制升级有以下几点注意事项:

Important

1. 设备单备份升级在传输Loader系统完成后,假如出现升级失败,设备会进入强制升级模式(既此刻设备会一直跑Loader系统,非正常系统),我们只需要对强制升级设备进行升级,升级成功后就可以正常使用。
2. 设备进入Loader系统后,通常情况下,是不支持固件端其余功能,包括自定义的命令通讯交互。需特殊处理,请跟固件开发人员沟通。
3. 如果应用开发时,对蓝牙连接有特殊处理(举例:连接应答的命令机制,超时断开),需要特殊考虑强制升级设备的情况,进行处理。
举例处理:应用需求-蓝牙连接时,App向设备发送连接命令,设备若超时没有回复连接命令 ,App端主动断开设备。
当设备是强制升级设备且是新回连广播包时,我们可通过广播包判断出该设备是强制升级设备,直接跳过连接应答机制。
当设备是强制升级设备且是旧回连广播包时,我们需要先连接上设备,通过RCSP-SDK获取到设备信息,才可判断设备是不是强制升级设备,视情况跳过连接应答机制。
4. 若打开认证,进入强制升级模式后(包括升级过程中的回连),连接设备也需要先进行认证,才能进行RCSP通讯。

关于单备份如何检查设备是否需要强制升级:

Important

检验设备是否需要强制升级,可用以下几种方式进行:
1.连接上设备后,传输连接状态给RCSP-SDK( RcspOpImpl.transmitDeviceStatus() )。当OnRcspCallback 回调初始化成功后( OnRcspCallback.onRcspInit() ),上层可获取设备信息( RcspOpImpl.getDeviceInfo() ),设备信息中包含了是否需要强制升级( deviceInfo.mandatoryUpgradeFlag==1 )
2.连接上设备后,传输连接状态给RCSP-SDK( RcspOpImpl.transmitDeviceStatus() )。当OnRcspCallback 回调需要强制升级时( OnRcspCallback.onMandatoryUpgrade() ) ,则表示该设备需要强制升级。不需要强制升级的设备是不会回调的。
3.当设备端使用的是升级新回连广播包时,只要收到该广播包就可以认为该设备需要强制升级。
4.在Loader系统内自定义命令交互(不推荐,理论可行)

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 注意事项

  1. 为了防止单备份升级失败导致固件变”砖”, 因此固件单备份升级失败后会进入强制升级模式

  2. 因为未连接设备时, 不知道设备状态, 所以库初始化成功后需要查询设备升级状态()

  3. 当连接上设备(若打开认证,需要先认证成功)后,可以将设备连接状态传输给RcspOpImpl

  4. 用户SDK或APP应该具备回连上一次连接的蓝牙设备的功能, 用于强制升级时自动回连设备, 再通过OTA升级更新固件

  5. 单备份方案,下载boot完成后,会先断开已连接的蓝牙(SPP或BLE), 进入uboot后,然后回连BLE

  6. 双备份方案, 不需要回连过程,直接开始升级流程