cordova(android ios) ota给蓝牙设备升级

官方指导

cordova蓝牙插件,总结

1.用cordova(javascript)实现的具体代码如下



//ota服务
var UUID_SERVICE_BLUEX_OTA
//ota控制特征
var UUID_CHARACTERISTIC_OTA_CTRL 
//ota数据特征
var UUID_CHARACTERISTIC_OTA_DATA 

if(navigator.platform == "iPhone"){
    UUID_SERVICE_BLUEX_OTA = '2600'
    UUID_CHARACTERISTIC_OTA_CTRL = '7000'
    UUID_CHARACTERISTIC_OTA_DATA = '7001'
}else{
 UUID_SERVICE_BLUEX_OTA = '00002600-0000-1000-8000-00805F9B34FB'
 UUID_CHARACTERISTIC_OTA_CTRL = '00007000-0000-1000-8000-00805F9B34FB'
 UUID_CHARACTERISTIC_OTA_DATA = '00007001-0000-1000-8000-00805F9B34FB'
}

var REQUEST_CTRL_OTA_START = 0    //刚开始发送文件数据之前先告诉设备,我要OTA,发文件了。
var RESPONSE_CTRL_OTA_START = 1   //设备接到手机端发来的信息,返回给手机我准备好了,发OTA文件来吧。
var REQUEST_CTRL_NEW_BLOCK = 2    //手机说:我要发一个新的数据块了。
var REQUEST_CTRL_DATA_FINISH = 3    //手机说:我把OTA文件都发完了。

function Segment() {}
Segment.prototype.index = 0
Segment.prototype.segBytes = [-1]


function Block() {}
Block.prototype.index = 0
Block.prototype.segments = [new Segment()]
Block.prototype.allBytesInBlock = [1,2]



var maxSegmentBytesLength = 19
var tasks = [] //blockarr
var currentBlockIndex = 0
var currentSegmentIndex = 0
var maxSegmentNumInBlock = 168
var firmware = []

function createTasks() {
    function addFullBlock() {
        for(var i = 0; i < blocksLength; i++) {
            var block = new Block()
            block.index = i
            block.allBytesInBlock = firmware.slice(i*maxBlockBytesLength, (i+1)*maxBlockBytesLength )
            parseBlock(block)
            blocks.push(block)
        }
    }
    var blocks = []
      //一个block(区块)的最大字节长度
    var maxBlockBytesLength = maxSegmentNumInBlock * maxSegmentBytesLength
    var blocksLength = parseInt(firmware.length / maxBlockBytesLength)
    if(firmware.length % maxBlockBytesLength == 0) {
        addFullBlock()
    } else {
        addFullBlock()
        var block = new Block()
        block.index = blocksLength
        block.allBytesInBlock = firmware.slice(blocksLength*maxBlockBytesLength, firmware.length)
        parseBlock(block)
        blocks.push(block)
    }
    tasks = blocks
}

function parseBlock(block) {
    var segments = []
    var index = parseInt(block.allBytesInBlock.length / maxSegmentBytesLength) 
    function addFullSegment() {
        for(var i = 0; i < index; i++) {
            var segment = new Segment()
            segment.index = i
            segment.segBytes = block.allBytesInBlock.slice(i*maxSegmentBytesLength, (i+1)*maxSegmentBytesLength)
            segments.push(segment)
        }
    }
    if(block.allBytesInBlock.length % maxSegmentBytesLength == 0) {
        addFullSegment()
    } else {
        addFullSegment()
        var segment = new Segment()
        segment.index = index
        segment.segBytes = block.allBytesInBlock.slice(index*maxSegmentBytesLength, block.allBytesInBlock.length)
        segments.push(segment)
    }
    block.segments = segments
}

function prepareAndStartOta() {
    console.log(currentMy.bleId)
    console.log(UUID_SERVICE_BLUEX_OTA)
    console.log(UUID_CHARACTERISTIC_OTA_CTRL)
    ble.startNotification(currentMy.bleId, UUID_SERVICE_BLUEX_OTA, UUID_CHARACTERISTIC_OTA_CTRL, otaReceiveBlueData, function(data){
        console.log("ota读取数据失败")
        console.log(data)
    }) 
    window.resolveLocalFileSystemURL(cordova.file.applicationDirectory, function (dirEntry) {  
        console.log('file system open: ' + dirEntry.name);  
        console.log(dirEntry); 
        console.log(dirEntry.nativeURL); 
        dirEntry.getFile("www/test.bin",{create : false},function(fileEntry){
            console.log(fileEntry)
            fileEntry.file(function (file) {
                var reader = new FileReader();
                reader.onloadend = function() {
                    console.log("Successful file read: " + this.result);
                    console.log(this.result)
                    // firmware = this.result
                   firmware = new Uint8Array(this.result)
                    startOta()
                };
        
                reader.readAsArrayBuffer(file);
            })
        },function(error){
            console.log(error)
        })
    }, function(){});   

    currentBlockIndex = -1
}

function startOta() {
    var startBytes = [REQUEST_CTRL_OTA_START, maxSegmentBytesLength, maxSegmentBytesLength >> 8]
    var crcHex = crc32(firmware)
    var lengthHex = firmware.length.toString(16)
    var arr1 = startBytes.concat(Str2Bytes(crcHex))
    var arr2 = arr1.concat(Str2Bytes(lengthHex))
    console.log(Bytes2Str(arr2))
    dataType = 0
     otaSendIntArr(arr2)   
}

//十六进制字符串转字节数组(反过来)
function Str2Bytes(str) {
    switch (str.length) {
        case 3:
            str = "00000" + str;
            break;
        case 4:
            str = "0000" + str;
            break;
        case 5:
            str = "000" + str;
            break;
        case 6:
            str = "00" + str;
            break;
        case 7:
            str = "0" + str;
            break;

    }
    var pos = 0;
    var len = str.length;
    len /= 2;
    var hexA = new Array();
    pos = len * 2 - 2
    for (var i = 0; i < len; i++) {
        var s = str.substr(pos, 2);
        var v = parseInt(s, 16);
        hexA.push(v);
        pos -= 2;
    }
    return hexA;
}

//字节数组转十六进制字符串
function Bytes2Str(arr) {
    var str = "";
    for (var i = 0; i < arr.length; i++) {
        var tmp = arr[i].toString(16);
        if (tmp.length == 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}

function otaReceiveBlueData(buffer) {
    var data = new Uint8Array(buffer);
    var intArr = uint8ArrToInt(data)
    console.log("ota收到数据")
    console.log(data)
    console.log(Bytes2Str(intArr))
    if(data[0] == RESPONSE_CTRL_OTA_START && data[1] == 0) {
        // maxSegmentNumInBlock = data[2]
        createTasks()
        console.log("设备说准备好了,开始升级")
        console.log("一共"+tasks.length+"个block")
        sendNewBlock()
    } else if (data[0] == REQUEST_CTRL_NEW_BLOCK) {
        // newBlock()
    } else {
        console.log("更新失败")
    }

}

function sendNewBlock() {
    if(currentBlockIndex + 1 == tasks.length) {
        sendFinish()
        return
    }
    currentBlockIndex++
    var newBlockArr = [REQUEST_CTRL_NEW_BLOCK, currentBlockIndex, currentBlockIndex >> 8]
    dataType = 1
    otaSendIntArr(newBlockArr)
}

function uint8ArrToInt(uint8Arr) {
    var arr = []
    for (var i = 0; i < uint8Arr.length; i++) {
        arr.push(uint8Arr[i])
    }
    return arr
}

function readDataAck() {
    ble.read(currentMy.bleId, UUID_SERVICE_BLUEX_OTA, UUID_CHARACTERISTIC_OTA_DATA,function(data){
        var intArr = uint8ArrToInt(new Uint8Array(data))
    
        var segmentNum = block.segments.length

        if(testDebug){
            console.log(Bytes2Str(intArr))
            console.log(segmentNum)
        }
       
        for(var i = 0; i < segmentNum; i++) {
            var sent = intArr[parseInt(i/8)] & (1 << (i%8)) != 0
            if(!sent){
                updateFailedShow()
                ble.disconnect(currentMy.bleId,function(){
                    console.log("断开连接成功");
                },function(data){
                    console.log("断开连接失败"+data)
                });
                return
            }
        }
        sendNewBlock()
    },function(data){
        updateFailedShow()
        console.log("read数据失败")
        console.log(data)
    })
}

function sendFinish(){
    var data = [REQUEST_CTRL_DATA_FINISH]
    dataType = 0
    console.log("finish")
    updateSuccessful()
    isUpdating = false
    otaSendIntArr(data)
}

function segmentNextStep() {
    var percent = currentSegmentIndex/(block.segments.length - 1)/tasks.length + currentBlockIndex /tasks.length
    var num = (percent*100).toFixed(1)
    $(".sofUpdateSpan").html(num+"%")
    if(isUpdating == false){
        //退出更新界面后会用到
        console.log("进来isUpdating")
        return
    }
    // console.log(num)
    currentSegmentIndex++
    transferSegment()

}



var block;
function newBlock() {
    currentSegmentIndex = 0
     block = tasks[currentBlockIndex]
     if(testDebug){
        console.log("第"+currentBlockIndex+"个block")
     }
    transferSegment()
}

function transferSegment() {
    if(currentSegmentIndex > block.segments.length - 1) {
        //校验
        readDataAck()
        return
    }
    var segBytes = uint8ArrToInt(block.segments[currentSegmentIndex].segBytes)
    var data = [currentSegmentIndex].concat(segBytes)
    otaSendIntArrData(data)
    
}

//现在发的是什么类型的数据 0:非block, 1:newBlock
var dataType = 0


function otaSendIntArr(intArr) {
    var sendData = new Uint8Array(intArr);
    if(testDebug){
        console.log("发ota数据")
        console.log(Bytes2Str(intArr))
    }

    ble.write(currentMy.bleId, UUID_SERVICE_BLUEX_OTA, UUID_CHARACTERISTIC_OTA_CTRL, sendData.buffer,function(data){
        // console.log("ota数据发成功")
        // console.log(data)
        if(dataType == 1){
            newBlock()
        }       

    },function(data){
        updateFailedShow()
        console.log("ota数据发失败")
        console.log(data)
    })
}

function otaSendIntArrData(intArr) {
    var sendData = new Uint8Array(intArr);
    // console.log("发ota数据")
    // console.log(Bytes2Str(intArr))
    ble.writeWithoutResponse(currentMy.bleId, UUID_SERVICE_BLUEX_OTA, UUID_CHARACTERISTIC_OTA_DATA, sendData.buffer,function(data){
        // console.log("ota数据发成功")
        var timer = setTimeout(function(time){
            segmentNextStep()
            clearTimeout(timer);
            },4);

    },function(data){
        updateFailedShow()
        console.log("ota数据发失败")
        console.log(data)
    })
}




1.1 打印截图

在这里插入图片描述
在这里插入图片描述

2.遇到的问题一:iOS设备(iphone)上搜不到要进行ota的服务,如下:

android手机:下图中的unknown Service就是进行ota的service
在这里插入图片描述
iphone: 在iphone上却找不到和android上用来ota的相同服务
请添加图片描述

2.1.猜想原因,android上和iOS上同一个服务展示出的uuid不同,安卓上是00002600-0000-1000-8000-00805F9B34FB,而iOS上是2600(亲测证明我的猜想是正确的)

3.遇到问题二:Writing is not permitted,总是写数据失败,解决方法:ble.writeWithoutResponse

Writing is not permitted

4.ota的校验,readAck()

校验代码代表的意思是,读取自己数组的每个元素的值都是0xff(255)

kotlin代码:

 val sent = acks[i / 8].and(1.shl(i % 8).toByte()).unsignedByteToInt() != 0
 if(sent){
 //校验成功
 }

javascript代码:

var sent = intArr[parseInt(i/8)] & (1 << (i%8)) != 0
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页