版本 | 修订记录 | 日期 | 修订者 |
---|---|---|---|
1.0 | 初稿 | 2019-07-31 | 翟智刚 |
[TOC]
1、升级文件说明
FUOTA.obin源文件示例
{"otaFile":{
"bin_dic":{
"0":{
"index":0,
"buffer":"AgAEAKoDMgQAAAA=",
"bufferstring":"02 00 04 00 AA 03 32 04 00 00 00"
},
"1":{
"index":0,
"buffer":"AgAEAKoDMgQAAAA=",
"bufferstring":"02 00 04 00 AA 03 32 04 00 00 00"
},
"2":{
"index":0,
"buffer":"AgAEAKoDMgQAAAA=",
"bufferstring":"02 00 04 00 AA 03 32 04 00 00 00"
},
"3":{
"index":0,
"buffer":"AgAEAKoDMgQAAAA=",
"bufferstring":"02 00 04 00 AA 03 32 04 00 00 00"
},
"4":{
"index":0,
"buffer":"AgAEAKoDMgQAAAA=",
"bufferstring":"02 00 04 00 AA 03 32 04 00 00 00"
},
},
"devEUI":[{"deveui_start":"0000000000000000","deveui_end":"0000000000000000"}],
"otaMode":"ota",
"otaPort":201,
"packets":5,
"intervalTime":5000,
"txCounts":1,
"swtime":2000,
"src":null,
"deviceIntervalTime":60000,
"dndata":null,
"appeui":"d896e0efff000000"}
}
.obin文件字段说明
参数 | 说明 |
---|---|
bin_dic | 待升级数据总包,由多包(子对象)构成。子对象key从0开始。 bufferstring 剔除空格后作为单播内容发送。 |
devEUI | 待升级节点devEUI范围。这个范围内的节点都需要升级。 |
otaPort | 下行端口和上行端口。目前都是201 |
packets | 升级文件分几包发送。值等于bin_dic的子对象个数,及包数。 |
intervalTime | 两个包发送的时间间隔。单位为毫秒。 |
deviceIntervalTime | 一个节点升级完成后,等待下一个节点升级的间隔。单位为毫秒。 |
appeui | 对应linkwan的joineui,可以做校验 |
说明:
其他属性FUOTA升级时暂不需要。
所有节点顺序升级。一个节点升级完成,再升级下一个节点。
一个节点的多个数据包,顺序发送。每个数据包至少发两遍(次数可配置)。
所有下发的数据包,内容取bufferstring字符串去掉空格,使用unconfirmed包,端口为otaPort。
判断一个节点升级成功的方法:在下发完所有数据包后,等待一段时间(可配置),收到此节点从otaPort端口有上行数据包,则升级成功;否则,升级失败。
LinkWan的SendUnicastCommand接口,数据包长度最大128个16进制字节。
201端口返回结果说明
节点升级成功后,201端口返回的数据
{
"devAddr": "66ae8469",
"rssi": -103,
"data": "8104000000FCFF008102130C16000240081820284733D00200000000",
"gwEui": "d896e0fff0105d0a",
"fcnt": 6,
"devEui": "d896e00005000151",
"joinPermissionId": 3674,
"mtype": 2, //0:join包,2:unconfirmed up 4:confirmed up
"datr": "SF9BW125",
"fport": 201,
"joinEui": "d896e0e000006946",
"snr": 8.0,
"time": 1569296961047,
"nodeGroupId": "102"
}
特别说明:下面是入网返回的数据,fport不存在,注意异常保护
{
"devAddr": "66ae8469",
"joinPermissionId": 3674,
"mtype": 0,
"rssi": -101,
"datr": "SF10BW125",
"joinEui": "d896e0e000006946",
"snr": 13.0,
"gwEui": "d896e0fff0105d0b",
"time": 1569296837194,
"nodeGroupId": "102",
"devEui": "d896e00005000151"
}
data十六进制数据含义说明
索引 | 内容 | 含义 | 备注 |
---|---|---|---|
0 | 81 | 固定为81,表示Fuota升级完成。暂不使用。 | |
1 | 04 | ||
2 | 00 | ||
3 | 00 | ||
4 | 00 | ||
5 | FC | ||
6 | FF | ||
7 | 00 | 0表示Fuota升级成功,1表示Fuota升级失败。 | |
8 | 81 | 低4位:Fuota版本号;高4位:硬件类型低4位值 | 从8~15,对应app参数的前8个字节 |
9 | 02 | 硬件类型高8位,因此硬件类型为:28,即40。硬件类型共12位长度。 | |
10 | 13 | 高4位:硬件版本1。低4位:3*4=12,表示从app参数索引12开始的字节数。 | |
11 | 0C | 软件版本号:12 | |
12 | 16 | 设备类型低8位 | 22:天鹅制冷热泵 |
13 | 00 | 设备类型高8位 | |
14 | 02 | 业务参数版本号,也就是obin文件的版本号 | |
15 | 40 | ||
16 | 08 | 485通信波特率除以1200,8表示波特率为9600 | 16~,对应APP参数第12个字节开始的内容,字节数=索引10的低4位*4 |
17 | 18 | bit0-bit3:数据位;bit4-bit5:停止位;bit6-bit7:校验位 | |
18 | 20 | bit0:485始终处于接收状态;bit1:电池供电;bit2:使用Uart1;bit3:读取超时;bit4-bit6:上传模式 | |
19 | 28 | confirmDuty | |
20 | 47 | ||
21 | 33 | 透传端口 | |
22 | D0 | 自动复位时间,低8位。单位为小时。 | 2D0表示每720个小时DTU会自动复位 |
23 | 02 | 自动复位时间,高8位。单位为小时。 | |
24 | 00 | ||
25 | 00 | ||
26 | 00 | ||
27 | 00 |
说明:obin文件中从第二包数据的第8个字节开始,共16个字节,应该与201端口上来的数据第9个字节开始共16个字节的数据完全一致。升级成功的判断条件为:索引7内容为0,并且索引14的内容等于obin文件packet1的第14个字节内容(packet1的索引13)
升级结果转义JS脚本入参与返回json对象
入参:
//注入一个packet1参数,取值为obin文件中otaFile.bin_dic.1.bufferstring字符串;
packet1 = "08 00 00 02 00 00 00 81 02 13 0C 16 00 02 70 08 18 20 28 47 33 D0 02 00 00 00 00 55 00 84 02 16 05 05 06 00 0F 04 01 0D 09 00 00 01 00 05 00 0A 00 E8 03 64 00 FF FF FF FF FF 01 03 00 17 22 18 C8 B8 6B 00 00 00 00 00 00 00 00 00 00 2C 01 01 00 00 00";
//201端口返回的data数据
data201="8104000000FCFF008102130C16000240081820284733D00200000000",
返回结果:
{
"code":1,
"result":{
"fuotaVersion":1,
"hardwareType":40.0,
"hardwareVersion":1,
"softwareVersion":12.0,
"deviceType":22.0,
"bizParamVersion":2.0,
"info":"{\"app12Size\":{\"name\":\"app索引12开始的字节数\",\"value\":12},\"baudrate\":{\"name\":\"485通信波特率\",\"value\":9600},\"dataBits\":{\"name\":\"数据位\",\"value\":8},\"stopBits\":{\"name\":\"停止位\",\"value\":1},\"checkBits\":{\"name\":\"校验位\",\"value\":0},\"stats485\":{\"name\":\"485始终处于接收状态\",\"value\":0},\"battery\":{\"name\":\"电池供电\",\"value\":0},\"uart1\":{\"name\":\"使用Uart1\",\"value\":0},\"readTimeout\":{\"name\":\"读取超时\",\"value\":2},\"uploadMode\":{\"name\":\"上传模式\",\"value\":40},\"confirmDuty\":{\"name\":\"confirmDuty\",\"value\":40},\"transformPort\":{\"name\":\"透传端口\",\"value\":51},\"autoResetInterval\":{\"name\":\"自动复位时间(单位:小时)\",\"value\":720},\"data\":{\"name\":\"data\",\"value\":\"8104000000FCFF008102130C16000240081820284733D00200000000\"}}"
}
}
转换js脚本
/**
* 转换升级时201或214端口返回的数据
* @param packet1 obin文件中otaFile.bin_dic.1.bufferstring字符串;
* @param up_data 201或214端口返回的json中的data段
* @returns {{code: number}} 0升级失败;1升级成功
*/
function change(packet1, up_data, fport) {
var change201 = function (data) {
var result = {};
//data内容
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//81 04 00 00 00 FC FF 00 81 02 13 0C 16 00 02 40 08 18 20 28 47 33 D0 02 00 00 00 00
var tmp = 0;
//Fuota版本号
result.fuotaVersion = data[8] & 15;
tmp = data[8]>>4;
//>>0操作只是为了去掉整数小数点后面的0
//硬件类型
result.hardwareType = tmp + data[9]*16;
//硬件版本号
result.hardwareVersion = data[10] >> 4;
//硬件版本号
result.softwareVersion = data[11];
//设备类型
result.deviceType = data[12] + data[13]*256;
//业务参数版本号
result.bizParamVersion = data[14];
var info = {};
info.app12Size = {name:"app索引12开始的字节数", value: (data[10] & 15)*4};
//app从第12个字节开始的内容
info.baudrate = {name:"485通信波特率", value:data.length>=17?data[16]*1200:null};
info.dataBits = {name:"数据位", value:data.length>=18?data[17]&15:null};
info.stopBits = {name:"停止位", value:data.length>=18?(data[17]&48)>>4:null};
info.checkBits = {name:"校验位", value:data.length>=18?(data[17]&192)>>6:null};
info.stats485 = {name:"485始终处于接收状态", value:data.length>=19?data[18]&1:null};
info.battery = {name:"电池供电", value:data.length>=19?(data[18]&2)>>1:null};
info.uart1 = {name:"使用Uart1", value:data.length>=19?(data[18]&4)>>2:null};
info.readTimeout = {name:"读取超时", value:data.length>=19?(data[18]&112)>>4:null};
info.uploadMode = {name:"上传模式", value:data.length>=19?data[19]:null};
info.confirmDuty = {name:"confirmDuty", value:data.length>=20?data[19]:null};
info.transformPort = {name:"透传端口", value:data.length>=22?data[21]:null};
info.autoResetInterval = {name:"自动复位时间(单位:小时)", value:data.length>=24?data[23]*256+data[22]:null};
//原始数据data
info.data = {name:"data", value: up_data};
result.info = JSON.stringify(info);
return result;
};
var change214 = function (data) {
var result = {};
//data内容, data索引4-11对应fuota的索引8-15
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//2f 1a 00 18 81 02 13 0c 16 00 02 40 00 00 00 00 08 18 28 28 47 33 d0 02 00 00 00 00
var tmp = 0;
//Fuota版本号
result.fuotaVersion = data[4] & 15;
tmp = data[4]>>4;
//>>0操作只是为了去掉整数小数点后面的0
//硬件类型
result.hardwareType = tmp + data[5]*16;
//硬件版本号
result.hardwareVersion = data[6] >> 4;
//硬件版本号
result.softwareVersion = data[7];
//设备类型
result.deviceType = data[8] + data[9]*256;
//业务参数版本号
result.bizParamVersion = data[10];
result.info = "{}";
return result;
};
var res = {code:0};
var data = [];
for(var i=0;i<up_data.length/2;i++){
data.push(parseInt(up_data.substr(i*2,2), 16));
}
if(fport == 201){
var arrPacket1 = packet1.split(" ").map(function (a) {
return parseInt(a, 16);
});
//判断升级是否成功
if(data[7]==0 && data[14] == arrPacket1[13]){
res.code = 1;
}else {
res.code = 0;
}
res.result = change201(data);
}else if(fport == 214){
res.code = 1;
res.result = change214(data);
}
return res;
};
2、节点任务状态机
状态表
状态值 | 名称 | 含义 |
---|---|---|
10 | 升级中 UPGRADING |
至少已发送了一个包,最后一个包还未发送。 |
20 | 待升级 READY |
刚创建的任务,或将未成功、终止、失败的任务重置为待升级。 |
30 | 未成功 UNSUCCESSFUL |
升级检查结果为不成功,重试次数未用完。 |
40 | 已发完 SENT |
一个节点的所有包已发送完毕,等待查询升级结果。 |
50 | 成功 SUCCESSFUL |
检查升级结果成功。升级结束。 |
60 | 终止 STOPPED |
升级任务终止。升级结束。 |
70 | 失败 FAILED |
升级检查升级结果不成功,重试次数已用完。升级结束。 |