SOTA升级

中国电信物联网使能平台(以下简称“平台”)提供了基于LWM2M的固件升级功能,用于模组的固件升级。但是由于多数模组并未提供升级接口给MCU,所以MCU升级只能基于应用层来实现升级,为了避免和模组的升级混淆,我们把MCU的升级称为软件升级。

支持LWM2M协议的设备升级。

1.1软件包

平台对升级的软件有格式要求,厂商需要根据软件包制作规范制作软件包,并上传到平台。

1.1.1软件包制作

1、准备升级软件包文件

设备厂商自行发布用于设备升级的软件包版本文件。

【说明】:需要将所有要在升级时传给设备的软件版本文件都打成一个升级文件。

【注】:软件包文件名称不支持包含中文字符。

2、制作设备升级版本包

步骤 1新建文件夹命名为"DM",在DM文件夹下创建设备系统类型文件夹,例如嵌入式设备通常采用"linux",将厂商发布的软件包描述文件"UpgradeDesc.json"文件至于"linux"目录下,参见下图:

UpgradeDesc.json文件字段说明参见下表,文件编码格式为UTF-8无BOM。

字段名 字段描述 是否必填
specVersion 描述文件版本号,固定值:"1.0"
fileName 软件包文件名,例如:ExamplePackage_V1.0.xx
version 软件包版本号备注:升级协议类型为PCP的设备软件版本号长度不超过16个字节
deviceType 设备类型
manufacturerName 制造商名称
model 产品型号
packageType 软件包必须设置为:"softwarePackage"
protocolType 设备接入协议类型,例如:"CoAP"
date 出包时间,格式为:"yyyy-MM-dd"
description 对软件包的自定义描述
supportSourceVersionList List<SupportSourceVersion>支持用于升级此版本包的设备源版本列表。不配置该字段说明该版本可用于任意源版本进行升级(具体见下表)
versionCheckCode 设备厂商出包时用于版本包校验的校验码说明:该字段有配置的话,在平台通知设备做版本下载时会将该字段作为参数发送给设备,由设备侧自行进行版本校验。发送给设备时会转换成16进制,限制2字符或者4字符。
deviceShard 终端下载软件包的每个分片的大小,单位为byte,如果不设置默认为500byte。大小为32~500之间。

SupportSourceVersion的字段说明

字段名 字段描述 是否必填
swVersion 支持用于升级此版本包的设备源软件版本号。支持通配符配置,*代表匹配任意0~n个字符,?代表匹配单个任意字符

步骤 2在与"DM"同级目录下创建平台类型文件夹,例如"linux",该文件夹名称必须同步骤1中的平台类型文件夹一致,将厂商软件包至于该目录,参见下图

UpgradeDesc.json文件模板如下:

{

"specVersion": "1.0",

"fileName": "ExamplePackage_V1.0.xx",

"packageType": "softwarePackage",

"version": "V1.0",

"deviceType": "BikeLock",

"manufacturerName": "ofo",

"model": "twx2",

"protocolType":"CoAP",

"description":"Test software package",

"versionCheckCode":"e4",

"deviceShard":"128",

"date":"2017-08-11"

}

步骤 3选中"DM"和"linux"文件夹,使用winRAR等压缩工具打包成ZIP格式的压缩包package.zip(注意package.zip下不能包含package这层目录,如图8-1-3所示。不能压缩成其他格式例如rar然后在手动修改文件类型为zip)

步骤 4选中“package.zip”再次使用7-ZIP等压缩工具打包成ZIP格式的压缩包package.zip(注意,这里是将package.zip再次压缩打包,形成双层zip文件包)

1.1.2软件包上传

1、软件包上传

登录物联网平台的控制台>远程升级管理。

选择SOTA升级>升级包管理>创建升级包,将升级包信息上传至云端。

升级包版本名称和升级包版本号需要按格式填写。

需保证升级包大小1M以内。

按照提示填写相关信息即可。

1.2平台升级协议

本协议规定设备和中国电信物联网开放平台之间的应用层升级协议

(简称PCP协议),用于实现设备的升级。更多详情请咨询物联网运营人员。

1.3软件升级操作流程

1)操作步骤

第一步:

登录物联网平台的控制台>远程升级管理。

选择SOTA升级>升级包管理>创建升级包,将升级包信息上传至云端。

升级包版本名称和升级包版本号需要按格式填写。

需保证升级包大小1M以内。

第二步:

选择SOTA升级>创建任务,开始创建升级任务。

第三步:

选择SOTA升级>升级设备管理,开始加入待升级设备。

第四步:

确认已选择设备。

第五步:

选择SOTA升级>开始启动,开始启动升级任务。

第六步:

选择FOTA升级>查看设备升级详情,可以查看设备升级的状态和结果。

2)任务状态说明

未执行:任务未启动。

执行中:正在升级,存在未完成的任务。

已完毕:全部升级任务都达到终止状态,升级完成或升级失败。

1.4软件升级CRC16算法模板

【软件升级】CCITT标准CRC16(1021)算法Java代码:

public class CRC16Util {
private static int crc16_ccitt_table[] = {
 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a,
                    0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
                    0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528,
                    0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719,
                    0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e,
                    0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf,
                    0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec,
                    0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd,
                    0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2,
                    0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3,
                    0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0,
                    0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691,
                    0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806,
                    0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37,
                    0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64,
                    0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55,
                    0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 
};


    /**
     *
     * @param reg_init CRC校验时初值
     * @param message 校验值
     * @return
     */
    public static int do_crc(int reg_init, byte[] message) {
        int crc_reg = reg_init;
        for (int i = 0; i < message.length; i++) {
            crc_reg = (crc_reg >> 8) ^ crc16_ccitt_table[(crc_reg ^ message[i]) & 0xff];
        }
        return crc_reg;
    }

    /**
     * 根据数据生成CRC校验码
     *
     * @param message
     *            byte数据
     *
     * @return int 返校验码
     */
    public static int do_crc(byte[] message) {
        // 计算CRC校验时初值从0x0000开始。
        int crc_reg = 0x0000;
        return do_crc(crc_reg, message);
    }
    /**
     * db44检验方法
     *
     * @param message 消息内容
     * @param crc 检验码值
     * @return
     */
    private static boolean do_crc(byte[] message,byte[] crc) {
        // 计算CRC校验时初值从0x0000开始。
        int crc_reg = 0x0000;
        int crc_value = (crc[0]&0xff)*256+(crc[1]&0xff);
        return crc_value ==do_crc(crc_reg, message);
    }
    /**
     * 供db44结构代码使用,数组后两位为CRC-校验码值
     * @param messages
     * @return
     */
    public static boolean do_crc_db44(byte[] messages) {
        // 计算CRC校验时初值从0x0000开始。
        byte[] messageArray = new byte[messages.length-2];
        byte[] crcArray = new byte[2];
        System.arraycopy(messages, 0, messageArray, 0, messageArray.length);
        System.arraycopy(messages, messages.length-2, crcArray, 0, 2);
        return do_crc(messageArray, crcArray);
    }

    public static void main(String[] args) {
        //以FFFE011300000000为例
        byte[] bytes = new byte[]{(byte)0xFF,(byte)0xFE,0x01,0x13,0x00,0x00,0x00,0x00};
        ByteBuffer clone = ByteBuffer.wrap(bytes);
        //需要把校验码的值置0再进行计算
        //clone.put(4, (byte)0).put(5, (byte)0);
        int calcChecksum = CRC16Util.do_crc(clone.array());
        System.out.println("calcChecksum:"+Integer.toHexString(calcChecksum));
    }
}

例如使用“FFFE011300000000”计算出来的校验码是4C9A,把校验码替换到软件升级码流规定的位置得到:FFFE011300000000->FFFE01134C9A0000,这个就是平台下发的查询设备软件版本的码流了

【软件升级】CCITT标准CRC16(1021)算法C语言代码:

#include <stdio.h>
typedef unsigned char byte;

const unsigned short crc16_table[256] = {
        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
        0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
        0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
        0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
        0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
        0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
        0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
        0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
        0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
        0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
        0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
        0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
        0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
        0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
        0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
        0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
        0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
        0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
        0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
        0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
        0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
        0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
        0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
        0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
        0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
        0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
        0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
        0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
        0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
        0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
        0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
        0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

int do_crc(int reg_init, byte* data, int length)
{
    int cnt;
    int crc_reg = reg_init;
    for (cnt = 0; cnt < length; cnt++)
    {
        crc_reg = (crc_reg >> 8) ^ crc16_table[(crc_reg ^ *(data++)) & 0xFF];
    }
    return crc_reg;
}

int main()
{
    // FFFE011300000000用byte数组表示:
    byte message[8] = {0xFF,0xFE,0x01,0x13,0x00,0x00,0x00,0x00};
    // 计算CRC校验时初值从0x0000开始
    int a = do_crc(0x0000, message,sizeof(message));
    printf("a ==> %x\n", a);
}

例如使用“FFFE011300000000”计算出来的校验码是4C9A,把校验码替换到软件升级码流规定的位置得到:FFFE011300000000->FFFE01134C9A0000,这个就是平台下发的查询设备软件版本的码流了

搜索结果 ""

    没有搜索结果 ""