xiuos/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c

1454 lines
58 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file: ota.c
* @brief: file ota.c
* @version: 1.0
* @author: AIIT XUOS Lab
* @date: 2023/4/23
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <transform.h>
#include "shell.h"
#include "boot_for_ota.h"
#include "ymodem.h"
#include "ota.h"
#ifdef CONNECTION_ADAPTER_4G
#include <adapter.h>
#endif
#ifdef OTA_BY_PLATFORM
#include "platform_mqtt.h"
#endif
#ifdef USING_DOWNLOAD_JSON
#include "cJSON.h"
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static uint32_t calculate_crc32(uint32_t addr, uint32_t len);
static int create_version(uint8_t* cur_version, uint8_t* new_version);
static status_t UpdateOTAFlag(ota_info_t *ptr);
static void InitialVersion(void);
static void BackupVersion(void);
static bool UpdateNewApplication(void);
static void Update(void);
static void BootLoaderJumpApp(void);
/****************************************************************************
* Private Data
****************************************************************************/
static const mcuboot_t mcuboot =
{
mcuboot_bord_init,
UartConfig,
Serial_PutString,
FLASH_Init,
FLASH_DeInit,
Flash_Erase,
Flash_Write,
Flash_Read,
Flash_Copy,
SerialDownload,
mcuboot_reset,
mcuboot_jump,
mcuboot_delay
};
static const uint32_t crc32tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
/*******************************************************************************
* 函 数 名: calculate_crc32
* 功能描述: 计算给定Flash内存地址范围中数据的CRC32校验和
* 形 参: addr:表示Flash地址的起始位置
len:表示需要计算CRC32的数据长度
* 返 回 值: 计算得到的CRC32值
*******************************************************************************/
static uint32_t calculate_crc32(uint32_t addr, uint32_t len)
{
uint32_t crc = 0xFFFFFFFF;
uint8_t byte = 0xFF;
for(uint32_t i = 0; i < len; i++)
{
byte = *((volatile uint8_t *)(addr + i));
crc = crc32tab[(crc ^ byte) & 0xff] ^ (crc >> 8);
}
return crc^0xFFFFFFFF;
}
/*******************************************************************************
* 函 数 名: create_version
* 功能描述: 根据当前版本号生成新的三段式版本号,适用于iap方式和TCPSERVER
* 形 参: cur_version:当前版本号,new_version:生成的新版本号
* 返 回 值: 0:生成成功,-1:生成失败
* 说 明: 为保持一致,平台通过OTA传输而来的版本号也要保持这样三段式的形式
版本形式为major.minor.patch,如001.002.003
*******************************************************************************/
static int create_version(uint8_t* cur_version, uint8_t* new_version)
{
int major, minor, patch; //三段式版本号的各个部分
//解析当前版本号,版本号格式不对直接返回
if (sscanf(cur_version, "%03d.%03d.%03d", &major, &minor, &patch) != 3) {
return -1;
}
//将当前版本号加1
patch++;
if(patch > 999)
{
minor++;
patch = 0;
if(minor > 999)
{
major++;
minor = 0;
patch = 0;
if(major > 999)
{
return -1;
}
}
}
//更新版本号
sprintf(new_version, "%03d.%03d.%03d", major, minor, patch);
return 0;
}
/*******************************************************************************
* 函 数 名: UpdateOTAFlag
* 功能描述: 更新OTA Flag区域的信息版本完成下载后在app里进行调用
* 形 参: ptr:ota_info_t结构体指针,描述OTA升级相关信息
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success否则状态值为其他错误码
*******************************************************************************/
static status_t UpdateOTAFlag(ota_info_t *ptr)
{
status_t status;
status = mcuboot.op_flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
if(status != kStatus_Success)
{
return status;
}
status = mcuboot.op_flash_write(FLAG_FLAH_ADDRESS,(void *)ptr,sizeof(ota_info_t));
return status;
}
/*******************************************************************************
* 函 数 名: InitialVersion
* 功能描述: 该函数可以烧写APP分区的初始化版本,初始化版本的版本号为0x1
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void InitialVersion(void)
{
int32_t size;
ota_info_t ota_info;
memset(&ota_info, 0, sizeof(ota_info_t));
size = mcuboot.download_by_serial(XIUOS_FLAH_ADDRESS);
if(size > 0)
{
ota_info.os.size = size;
ota_info.os.crc32 = calculate_crc32(XIUOS_FLAH_ADDRESS, size);
strncpy(ota_info.os.version,"001.000.000",sizeof(ota_info.os.version));
strncpy(ota_info.os.description, "The initial firmware.", sizeof(ota_info.os.description));
UpdateOTAFlag(&ota_info);
}
}
/*******************************************************************************
* 函 数 名: BackupVersion
* 功能描述: 版本回退函数,如果升级的APP存在bug导致无法跳转需调用此函数进行版本回退
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void BackupVersion(void)
{
status_t status;
ota_info_t ota_info;
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_BACKUP;
UpdateOTAFlag(&ota_info);
// 1.先清空XiUOS System分区
status = mcuboot.op_flash_erase(XIUOS_FLAH_ADDRESS, ota_info.os.size);
if(status == kStatus_Success)
{
memset(&ota_info.os,0,sizeof(ota_info.os));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Clear app partition success!------\r\n");
}
else
{
mcuboot.print_string("\r\n------Clear app partition failed!------\r\n");
return;
}
// 2.拷贝backup分区到XiUOS System分区
status = mcuboot.op_flash_copy(BAKUP_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.bak.size);
if(status == kStatus_Success)
{
ota_info.os.size = ota_info.bak.size;
ota_info.os.crc32 = ota_info.bak.crc32;
memset(ota_info.os.version,0,sizeof(ota_info.os.version));
strncpy(ota_info.os.version, ota_info.bak.version, sizeof(ota_info.bak.version));
memset(ota_info.os.description,0,sizeof(ota_info.os.description));
strncpy(ota_info.os.description, ota_info.bak.description, sizeof(ota_info.bak.description));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Version rollback successful!------\r\n");
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Version rollback failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Version rollback failed!------\r\n");
}
}
/*******************************************************************************
* 函 数 名: UpdateNewApplication
* 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新
* 形 参: 无
* 返 回 值: true:需要升级,发生了flash搬移的操作,不代表升级的结果
false:不需要升级,未发生flash搬移
* 注 释: 该函数调用后如果不需要升级APP分区保持不变,否则APP分区的版本为新版本
*******************************************************************************/
static bool UpdateNewApplication(void)
{
status_t status;
ota_info_t ota_info; // 定义OTA信息结构体
memset(&ota_info, 0, sizeof(ota_info_t));
// 从Flash中读取OTA信息
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
// 如果OTA升级状态为准备状态,且APP分区与download分区版本不同,才需要进行升级
if((ota_info.status == OTA_STATUS_READY) && (ota_info.os.crc32 != ota_info.down.crc32))
{
mcuboot.print_string("\r\n------Start upgrading to new version!------\r\n");
// 校验downlad分区固件CRC
if(calculate_crc32(DOWN_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32)
{
ota_info.status = OTA_STATUS_UPDATING;
UpdateOTAFlag(&ota_info);
// 1.如果CRC校验通过,开始升级,先清空Backup分区
status = mcuboot.op_flash_erase(BAKUP_FLAH_ADDRESS, ota_info.bak.size);
if(status == kStatus_Success)
{
memset(&ota_info.bak,0,sizeof(ota_info.bak));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Clear backup partition success!------\r\n");
}
else
{
mcuboot.print_string("\r\n------Clear backup partition failed!------\r\n");
goto finish;
}
// 2.逐字节拷贝Flash,备份当前XiUOS System分区内容到Backup分区
status = mcuboot.op_flash_copy(XIUOS_FLAH_ADDRESS, BAKUP_FLAH_ADDRESS, ota_info.os.size);
if((status == kStatus_Success) &&(calculate_crc32(BAKUP_FLAH_ADDRESS, ota_info.os.size) == ota_info.os.crc32))
{
ota_info.bak.size = ota_info.os.size;
ota_info.bak.crc32 = ota_info.os.crc32;
memset(ota_info.bak.version,0,sizeof(ota_info.bak.version));
strncpy(ota_info.bak.version, ota_info.os.version, sizeof(ota_info.os.version));
memset(ota_info.bak.description,0,sizeof(ota_info.bak.description));
strncpy(ota_info.bak.description, ota_info.os.description, sizeof(ota_info.os.description));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Backup app success!------\r\n");
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Backup app failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Backup app failed!------\r\n");
goto finish;
}
// 3.清空XiUOS System分区
status = mcuboot.op_flash_erase(XIUOS_FLAH_ADDRESS, ota_info.os.size);
if(status == kStatus_Success)
{
memset(&ota_info.os,0,sizeof(ota_info.os));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Clear app partition success!------\r\n");
}
else
{
mcuboot.print_string("\r\n------Clear app partition failed!------\r\n");
goto finish;
}
// 4.拷贝download分区到XiUOS System分区
status = mcuboot.op_flash_copy(DOWN_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.down.size);
if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32))
{
ota_info.os.size = ota_info.down.size;
ota_info.os.crc32 = ota_info.down.crc32;
memset(ota_info.os.version,0,sizeof(ota_info.os.version));
strncpy(ota_info.os.version, ota_info.down.version, sizeof(ota_info.down.version));
memset(ota_info.os.description,0,sizeof(ota_info.os.description));
strncpy(ota_info.os.description, ota_info.down.description, sizeof(ota_info.down.description));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------The download partition is copied successfully!------\r\n");
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "The download partition copy failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------The download partition copy failed!------\r\n");
goto finish;
}
// 5.清空download分区
status = mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS, ota_info.down.size);
if(status == kStatus_Success)
{
memset(&ota_info.down,0,sizeof(ota_info.down));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Clear download partition success!------\r\n");
}
else
{
mcuboot.print_string("\r\n------Clear download partition failed!------\r\n");
goto finish;
}
ota_info.status == OTA_STATUS_IDLE; //将OTA升级状态设置为IDLE
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------New version upgrade completed,reboot again!------\r\n");
goto finish;
}
else
{
// 如果download分区CRC校验失败,升级失败
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Download Firmware CRC check failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------Download Firmware CRC check failed!------\r\n");
goto finish;
}
}
else
{
// 如果OTA升级状态为准备状态但APP分区与download分区版本相同,不需要进行升级,重置status,打印提示信息
if((ota_info.status == OTA_STATUS_READY) && (ota_info.os.crc32 == ota_info.down.crc32))
{
ota_info.status == OTA_STATUS_IDLE;
UpdateOTAFlag(&ota_info);
mcuboot.print_string("\r\n------The app partition is the same as the download partition, no need to upgrade!------\r\n");
}
return false;
}
finish:
return true;
}
/*******************************************************************************
* 函 数 名: Update
* 功能描述: 根据实际情况进行初始化版本的烧录或者新版本的升级
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void Update(void)
{
ota_info_t ota_info;
mcuboot.flash_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
/* APP分区无有效固件时,需在bootloader下烧写初始固件, os.size大于分区大小视为无效固件*/
if(ota_info.os.size > APP_FLASH_SIZE)
{
mcuboot.print_string("\r\nNeed to flash initial firmware!\r\n");
InitialVersion();
mcuboot.flash_deinit();
}
/*进行新版本的升级*/
else
{
if(UpdateNewApplication() == true) /*如果实际发生了flash搬移,操作完成后再重启一次*/
{
mcuboot.flash_deinit();
mcuboot.op_delay(2000);
mcuboot.op_reset();
}
else /*如果实际未发生flash搬移,说明未发生实际的升级,操作完成后不必再重启*/
{
mcuboot.flash_deinit();
}
}
}
/*******************************************************************************
* 函 数 名: BootLoaderJumpApp
* 功能描述: 上次跳转若是失败的,先从BAKUP分区进行恢复,然后再进行跳转
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void BootLoaderJumpApp(void)
{
ota_info_t ota_info;
mcuboot.flash_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
if(ota_info.lastjumpflag == JUMP_FAILED_FLAG)
{
mcuboot.print_string("\r\n------Jump to app partition failed,start version rollback!------\r\n");
BackupVersion();
}
else
{
ota_info.lastjumpflag = JUMP_FAILED_FLAG;
UpdateOTAFlag(&ota_info);
}
mcuboot.flash_deinit();
mcuboot.op_jump();
}
/*********************************************************************************
* 函 数 名: app_ota_by_iap
* 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过串口iap方式传输bin文件
* 形 参: 无
* 返 回 值: 无
*********************************************************************************/
static void app_ota_by_iap(void)
{
int32_t size;
ota_info_t ota_info;
mcuboot.flash_init();
mcuboot.serial_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
size = mcuboot.download_by_serial(DOWN_FLAH_ADDRESS);
ota_info.status = OTA_STATUS_DOWNLOADED;
UpdateOTAFlag(&ota_info);
if(size > 0)
{
ota_info.down.size = size;
ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, size);
memset(ota_info.down.version,0,sizeof(ota_info.down.version));
create_version(ota_info.os.version, ota_info.down.version);
memset(ota_info.down.description,0,sizeof(ota_info.down.description));
strncpy(ota_info.down.description, "OTA Test bin.",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
mcuboot.flash_deinit();
MdelayKTask(2000);
mcuboot.op_reset();
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),iap, app_ota_by_iap, ota by iap function);
#ifdef OTA_BY_TCPSERVER
static uint16_t calculate_crc16(uint8_t * data, uint32_t len);
static void get_start_signal(struct Adapter* adapter);
static int ota_data_recv(struct Adapter* adapter);
static ota_data start_msg;
static ota_data recv_msg;
/*******************************************************************************
* 函 数 名: calculate_crc16
* 功能描述: 计算给定长度的数据的crc16的值,用于OTA传输过程中数据帧的校验
* 形 参: data:数据buffer
len:表示需要计算CRC16的数据长度
* 返 回 值: 计算得到的CRC16值
*******************************************************************************/
static uint16_t calculate_crc16(uint8_t * data, uint32_t len)
{
uint16_t reg_crc=0xFFFF;
while(len--)
{
reg_crc ^= *data++;
for(int j=0;j<8;j++)
{
if(reg_crc & 0x01)
reg_crc=reg_crc >>1 ^ 0xA001;
else
reg_crc=reg_crc >>1;
}
}
KPrintf("crc = [0x%x]\n",reg_crc);
return reg_crc;
}
/*******************************************************************************
* 函 数 名: get_start_signal
* 功能描述: 通过4G方式从服务端接收开始信号
* 形 参: adapter:Adapter指针,指向注册的4G设备
* 返 回 值: 0:传输成功,-1:传输失败
*******************************************************************************/
static void get_start_signal(struct Adapter* adapter)
{
ota_info_t ota_info;
uint8_t reply[16] = {0};
uint32_t flashdestination = DOWN_FLAH_ADDRESS;
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
while(1)
{
memset(&start_msg, 0, sizeof(ota_data));
/* step1:Confirm the start signal of transmission. */
KPrintf("waiting for start msg...\n");
if(AdapterDeviceRecv(adapter, &start_msg, sizeof(start_msg)) >= 0 && start_msg.header.frame_flag == STARTFLAG)
{
if(start_msg.header.total_len > APP_FLASH_SIZE)
{
KPrintf("File size is larger than partition size,the partition size is %dk.\n",APP_FLASH_SIZE/1024);
break;
}
if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,start_msg.header.total_len) != kStatus_Success)
{
KPrintf("Failed to erase target fash!\n");
break;
}
else
{
KPrintf("Erase flash successful,erase length is %d bytes.\n",start_msg.header.total_len);
}
memset(reply, 0, sizeof(reply));
memcpy(reply, "ready", strlen("ready"));
KPrintf("receive start signal,send [ready] signal to server\n");
while(AdapterDeviceSend(adapter, reply, strlen(reply)) < 0);
break;
}
else
{
memset(reply, 0, sizeof(reply));
memcpy(reply, "notready", strlen("notready"));
KPrintf("not receive start signal,send [notready] signal to server\n");
while(AdapterDeviceSend(adapter, reply, strlen(reply)) < 0);
continue;
}
}
}
/*******************************************************************************
* 函 数 名: ota_data_recv
* 功能描述: 通过4G方式从服务端接收数据
* 形 参: adapter:Adapter指针,指向注册的4G设备
* 返 回 值: 0:传输成功,-1:传输失败
*******************************************************************************/
static int ota_data_recv(struct Adapter* adapter)
{
ota_info_t ota_info;
uint8_t reply[16] = {0};
int ret = 0, frame_cnt = 0, try_times = 5;
uint32_t file_size = 0;
uint32_t flashdestination = DOWN_FLAH_ADDRESS;
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
while(1)
{
memset(&recv_msg, 0, sizeof(ota_data));
if(AdapterDeviceRecv(adapter, &recv_msg, sizeof(recv_msg)) >= 0)
{
if(recv_msg.header.frame_flag == STARTFLAG) //这里不应该再出现开始帧,丢弃当前数据继续接收
{
continue;
}
else if(recv_msg.header.frame_flag == DATAFLAG) //说明当前是bin包里数据封装成的数据帧
{
frame_cnt = recv_msg.frame.frame_id;
if(recv_msg.frame.crc == calculate_crc16(recv_msg.frame.frame_data,recv_msg.frame.frame_len))
{
KPrintf("current frame[%d],length %d bytes.\n",frame_cnt,recv_msg.frame.frame_len);
if(mcuboot.op_flash_write(flashdestination, recv_msg.frame.frame_data, recv_msg.frame.frame_len) != kStatus_Success)
{
KPrintf("current frame[%d] flash failed.\n",frame_cnt);
ret = -1;
break;
}
else
{
KPrintf("current frame[%d] is written to flash 0x%x address successful.\n", frame_cnt, flashdestination);
flashdestination += recv_msg.frame.frame_len;
}
}
else
{
KPrintf("current frame[%d] crc check failed,try again!\n",frame_cnt);
goto try_again;
}
}
else if(recv_msg.header.frame_flag == ENDTFLAG) //说明当前是结束帧
{
KPrintf("total %d frames %d bytes crc[0x%x],receive successful.\n",frame_cnt,recv_msg.header.total_len,recv_msg.frame.crc);
memset(reply, 0, sizeof(reply));
memcpy(reply, "ok", strlen("ok"));
AdapterDeviceSend(adapter, reply, strlen(reply));
ota_info.status = OTA_STATUS_DOWNLOADED;
UpdateOTAFlag(&ota_info);
file_size = recv_msg.header.total_len;
ret = 0;
break;
}
else //说明当前接收的数据帧不是上述三种数据帧的任意一种
{
goto try_again;
}
send_ok_again:
memset(reply, 0, sizeof(reply));
memcpy(reply, "ok", strlen("ok"));
ret = AdapterDeviceSend(adapter, reply, strlen(reply));
if(ret < 0)
{
KPrintf("send ok failed.\n");
goto send_ok_again;
}
KPrintf("send reply[%s] done.\n",reply);
//send ok后把try_times重置为5
try_times = 5;
continue;
}
//没有接收到数据或者接收到的数据帧不满足条件,需要发个retry的命令告诉服务器需要重传
else
{
try_again:
if(try_times == 0)
{
KPrintf("current frame[%d] try 5 times failed,break out!\n",frame_cnt);
ret = -1;
break;
}
memset(reply, 0, sizeof(reply));
memcpy(reply, "retry", strlen("retry"));
KPrintf("current frame[%d] receive failed. retry\n",frame_cnt);
AdapterDeviceSend(adapter, reply, strlen(reply));
try_times--;
continue;
}
}
//download分区固件下载成功,更新Flag分区
if(0 == ret)
{
ota_info.down.size = file_size;
ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, file_size);
memset(ota_info.down.version,0,sizeof(ota_info.down.version));
create_version(ota_info.os.version, ota_info.down.version);
memset(ota_info.down.description,0,sizeof(ota_info.down.description));
strncpy(ota_info.down.description, "4G OTA bin.",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
else
{
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
return ret;
}
/*******************************************************************************
* 函 数 名: app_ota_by_4g
* 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过4g方式传输bin文件
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void app_ota_by_4g(void)
{
uint32_t baud_rate = BAUD_RATE_115200;
uint8_t server_addr[16] = "115.238.53.60";
uint8_t server_port[8] = "7777";
mcuboot.flash_init();
struct Adapter* adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME);
adapter->socket.socket_id = 0;
AdapterDeviceOpen(adapter);
AdapterDeviceControl(adapter, OPE_INT, &baud_rate);
AdapterDeviceConnect(adapter, CLIENT, server_addr, server_port, IPV4);
MdelayKTask(100);
while(1)
{
/* step1:Confirm the start signal of transmission. */
get_start_signal(adapter);
KPrintf("start receive ota bin file.\n");
/* step2:start receive bin file,first wait for 4s. */
MdelayKTask(4000);
if(0 == ota_data_recv(adapter))
{
break;
}
}
mcuboot.flash_deinit();
KPrintf("firmware file transfer successful,start reboot!\n");
MdelayKTask(2000);
mcuboot.op_reset();
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),ota, app_ota_by_4g, ota by 4g function);
#endif
#ifdef OTA_BY_PLATFORM
#if (OTA_FRAME_SIZE <= MQTT_FRAME_SIZE)
#define FRAME_LEN OTA_FRAME_SIZE
#else
#error "The value of FRAME_LEN should not be greater than MQTT_FRAME_SIZE!!"
#endif
static uint8_t MqttRxbuf[FRAME_LEN + 1024];
static uint8_t FrameBuf[FRAME_LEN];
static OTA_TCB platform_ota;
/*******************************************************************************
* 函 数 名: displayProgress
* 功能描述: 显示当前ota下载进度的百分比
* 形 参: progress:当前下载的进度,0-100之间
* 返 回 值: 无
*******************************************************************************/
void displayProgress(uint8_t progress)
{
uint8_t buf[101];
if((progress >= 0) && (progress <= 100))
{
memset(buf, '=', progress);
buf[progress] = '\0';
KPrintf("[%-100s][%d%%]\r",buf,progress);
if(progress == 100)
KPrintf("\r\n---------------------------------------------\r\n");
}
}
#ifdef XIUOS_PLATFORM
/*******************************************************************************
* 函 数 名: PropertyVersion
* 功能描述: 向服务器上传当前设备版本信息
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void PropertyVersion(void)
{
uint8_t tempdatabuff[128];
ota_info_t ota_info;
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
memset(tempdatabuff,0,128);
sprintf(tempdatabuff,"{\"clientId\":\"%s\",\"version\":\"%s\"}",CLIENTID,ota_info.os.version);
KPrintf("------current version is:%s------\r\n",ota_info.os.version);
MQTT_PublishDataQs1("xiuosiot/ota/version",tempdatabuff,strlen(tempdatabuff)); //发送等级QS=1的PUBLISH报文
}
/*******************************************************************************
* 函 数 名: OTA_Download
* 功能描述: OTA下载数据
* 形 参: size:本次下载量,offset:本次下载偏移量
* 返 回 值: 无
*******************************************************************************/
static void OTA_Download(int size, int offset)
{
uint8_t tempdatabuff[128];
memset(tempdatabuff,0,128);
sprintf(tempdatabuff,"{\"clientId\":\"%s\",\"fileId\":%d,\"fileOffset\":%d,\"size\":%d}",Platform_mqtt.ClientID,platform_ota.streamId,offset,size);
MQTT_PublishDataQs0("xiuosiot/ota/files", tempdatabuff, strlen(tempdatabuff));
}
/*******************************************************************************
* 函 数 名: mqttCloudInteraction
* 功能描述: 设备通过MQTT协议与云平台交互
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void mqttCloudInteraction(void* parameter)
{
int datalen;
int ret = 0;
int freecnt = 0;
ota_info_t ota_info;
uint32_t heart_time = 0;
uint32_t flashdestination = DOWN_FLAH_ADDRESS;
uint8_t topicdatabuff[2][64];
char *ptr1, *ptr2;
uint16_t payloadLen;
mcuboot.flash_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
memset(topicdatabuff,0,sizeof(topicdatabuff));
sprintf(topicdatabuff[0],"ota/%s/update",CLIENTID);
sprintf(topicdatabuff[1],"ota/%s/files",CLIENTID);
reconnect:
if((AdapterNetActive() == 0) && MQTT_Connect() && MQTT_SubscribeTopic(topicdatabuff[0]) && MQTT_SubscribeTopic(topicdatabuff[1]))
{
KPrintf("Log in to the cloud platform and subscribe to the topic successfully.\n");
PropertyVersion();
}
else
{
KPrintf("Log in to the cloud platform failed, retry!\n");
goto reconnect;
}
#ifdef USING_DOWNLOAD_JSON
uint8_t jsontopicdatabuff[64];
uint8_t jsonfilename[32];
memset(jsontopicdatabuff,0,sizeof(jsontopicdatabuff));
sprintf(jsontopicdatabuff,"protocol/%s/files",CLIENTID);
if(!MQTT_SubscribeTopic(jsontopicdatabuff))
{
KPrintf("subscribe to the json download topic failed!\n");
}
#endif
while(1)
{
memset(MqttRxbuf,0,sizeof(MqttRxbuf));
datalen = MQTT_Recv(MqttRxbuf, sizeof(MqttRxbuf));
if(datalen <= 0)
{
freecnt++;
if((freecnt >= 20) && (CalculateTimeMsFromTick(CurrentTicksGain()) - heart_time >= HEART_TIME)) //连续20次未收到数据默认为为空闲状态,需每隔一段时间发送需要发送心跳包保活
{
heart_time = CalculateTimeMsFromTick(CurrentTicksGain());
freecnt = 0;
if(!MQTT_SendHeart()) //发送心跳包失败可能连接断开,需要重连
{
KPrintf("The connection has been disconnected, reconnecting!\n");
goto reconnect;
}
KPrintf("Send heartbeat packet successful!\n");
}
}
else if(MqttRxbuf[0] == 0x30)
{
freecnt = 0;
payloadLen = MQTT_DealPublishData(MqttRxbuf, datalen);
// 1.获取新版本固件大小及版本信息
ptr1 = strstr((char *)Platform_mqtt.cmdbuff,topicdatabuff[0]);
ptr2 = strstr((char *)Platform_mqtt.cmdbuff,"{\"fileSize\":");
if((ptr1 != NULL) &&(ptr2 != NULL))
{
if(sscanf(ptr2,"{\"fileSize\":%d,\"version\":\"%11s\",\"fileId\":%d,\"md5\"",&platform_ota.size,platform_ota.version,&platform_ota.streamId)==3)
{
KPrintf("OTA firmware information:file size is %d,file id is %d,file version is %s!\r\n",platform_ota.size,platform_ota.streamId,platform_ota.version);
KPrintf("------Start the firmware file transfer!------\r\n");
KPrintf("---------------------------------------------\r\n");
if(platform_ota.size > APP_FLASH_SIZE)
{
KPrintf("File size is larger than partition size,the partition size is %dk.\n",APP_FLASH_SIZE/1024);
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "File size is larger than partition size!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,platform_ota.size) != kStatus_Success)
{
KPrintf("Failed to erase download partition!\n");
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to erase download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
platform_ota.counter = (platform_ota.size%FRAME_LEN != 0)? (platform_ota.size/FRAME_LEN + 1):(platform_ota.size/FRAME_LEN);
platform_ota.num = 1; //下载次数,初始值为1
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else
{
KPrintf("Failed to get ota information!\n");
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to get ota information!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
}
// 2.分片接收新版本固件
if(strstr((char *)Platform_mqtt.cmdbuff,topicdatabuff[1]))
{
memset(FrameBuf,0,sizeof(FrameBuf));
memcpy(FrameBuf, &MqttRxbuf[datalen-platform_ota.downlen], platform_ota.downlen);
if(mcuboot.op_flash_write(flashdestination,FrameBuf,platform_ota.downlen) != kStatus_Success)
{
KPrintf("current frame[%d] flash failed.\n",platform_ota.num-1);
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
sprintf(ota_info.error_message,"current frame[%d] flash failed.",platform_ota.num-1);
UpdateOTAFlag(&ota_info);
break;
}
else
{
displayProgress((platform_ota.num*100)/platform_ota.counter);
flashdestination += platform_ota.downlen;
platform_ota.num++;
}
if(platform_ota.num < platform_ota.counter) //如果小于总下载次数
{
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else if(platform_ota.num == platform_ota.counter) //如果等于总下载次数,说明是最后一次下载
{
if(platform_ota.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍
{
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else
{
platform_ota.downlen = platform_ota.size%FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
}
else //下载完毕
{
ret = 0;
break;
}
}
#ifdef USING_DOWNLOAD_JSON
// 3.下载json文件,SD卡要确保已经插入并mount成功
extern bool GetSdMountStatus(void);
if(strstr((char *)Platform_mqtt.cmdbuff,jsontopicdatabuff) && GetSdMountStatus())
{
KPrintf("------Start download joson file !------\r\n");
memset(jsonfilename,0,sizeof(jsonfilename));
memset(FrameBuf,0,sizeof(FrameBuf));
memcpy(FrameBuf, &Platform_mqtt.cmdbuff[strlen(jsontopicdatabuff)],payloadLen-strlen(jsontopicdatabuff));
cJSON *json_obj = cJSON_Parse(FrameBuf);
char* product_name = cJSON_GetObjectItem(json_obj, "productName")->valuestring;
sprintf(jsonfilename,"%s",product_name);
strcat(jsonfilename,".json");
FILE *fp = fopen(jsonfilename, "w");
if(fp == NULL)
{
KPrintf("%s file create failed,please check!\r\n",jsonfilename);
cJSON_Delete(json_obj);
continue;
}
else
{
KPrintf("%s file create success!\r\n",jsonfilename);
char *json_print_str = cJSON_Print(json_obj);
fprintf(fp, "%s", json_print_str);
fclose(fp);
cJSON_free(json_print_str);
cJSON_Delete(json_obj);
}
KPrintf("------download %s file done!------\r\n",jsonfilename);
}
#endif
}
else
{
freecnt = 0;
continue;
}
}
// 新版本固件接收完毕,写入描述信息
if(0 == ret)
{
ota_info.down.size = platform_ota.size;
ota_info.down.crc32 = calculate_crc32(DOWN_FLAH_ADDRESS, platform_ota.size);
memset(ota_info.down.version,0,sizeof(ota_info.down.version));
strncpy(ota_info.down.version, platform_ota.version, sizeof(ota_info.down.version));
memset(ota_info.down.description,0,sizeof(ota_info.down.description));
strncpy(ota_info.down.description, "MQTT OTA bin.",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
KPrintf("firmware file transfer successful,start reboot!\n");
}
else
{
KPrintf("firmware file transfer failed,start reboot!\n");
}
MQTT_Disconnect();
mcuboot.flash_deinit();
MdelayKTask(2000);
mcuboot.op_reset();
}
#endif
#ifdef ALIBABA_PLATFORM
/*******************************************************************************
* 函 数 名: PropertyVersion
* 功能描述: 向服务器上传当前设备版本信息
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void PropertyVersion(void)
{
uint8_t topicdatabuff[64];
uint8_t tempdatabuff[128];
ota_info_t ota_info;
memset(topicdatabuff,0,64);
sprintf(topicdatabuff,"/ota/device/inform/%s/%s", PLATFORM_PRODUCTKEY, CLIENT_DEVICENAME);
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
memset(tempdatabuff,0,128);
sprintf(tempdatabuff,"{\"id\": \"1\",\"params\": {\"version\": \"%s\"}}",ota_info.os.version);
KPrintf("------current version is:%s------\r\n",ota_info.os.version);
MQTT_PublishDataQs1(topicdatabuff,tempdatabuff,strlen(tempdatabuff)); //发送等级QS=1的PUBLISH报文
}
/*******************************************************************************
* 函 数 名: OTA_Download
* 功能描述: OTA下载数据
* 形 参: size:本次下载量,offset:本次下载偏移量
* 返 回 值: 无
*******************************************************************************/
static void OTA_Download(int size, int offset)
{
uint8_t topicdatabuff[64];
uint8_t tempdatabuff[128];
memset(topicdatabuff,0,64);
sprintf(topicdatabuff,"/sys/%s/%s/thing/file/download",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME);
memset(tempdatabuff,0,128);
sprintf(tempdatabuff,"{\"id\": \"1\",\"params\": {\"fileInfo\":{\"streamId\":%d,\"fileId\":1},\"fileBlock\":{\"size\":%d,\"offset\":%d}}}",platform_ota.streamId,size,offset);
MQTT_PublishDataQs0(topicdatabuff, tempdatabuff, strlen(tempdatabuff));
}
/*******************************************************************************
* 函 数 名: mqttCloudInteraction
* 功能描述: 设备通过MQTT协议与云平台交互
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
static void mqttCloudInteraction(void* parameter)
{
int datalen;
int ret = 0;
int freecnt = 0;
ota_info_t ota_info;
uint32_t heart_time = 0;
uint32_t flashdestination = DOWN_FLAH_ADDRESS;
uint8_t topicdatabuff[2][64];
char *ptr1, *ptr2;
mcuboot.flash_init();
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.status = OTA_STATUS_DOWNLOADING;
UpdateOTAFlag(&ota_info);
memset(topicdatabuff,0,sizeof(topicdatabuff));
sprintf(topicdatabuff[0],"/ota/device/upgrade/%s/%s",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME);
sprintf(topicdatabuff[1],"/sys/%s/%s/thing/file/download_reply",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME);
reconnect:
if((AdapterNetActive() == 0) && MQTT_Connect() && MQTT_SubscribeTopic(topicdatabuff[0]) && MQTT_SubscribeTopic(topicdatabuff[1]))
{
KPrintf("Log in to the cloud platform and subscribe to the topic successfully.\n");
PropertyVersion();
}
else
{
KPrintf("Log in to the cloud platform failed, retry!\n");
goto reconnect;
}
while(1)
{
memset(MqttRxbuf,0,sizeof(MqttRxbuf));
datalen = MQTT_Recv(MqttRxbuf, sizeof(MqttRxbuf));
if(datalen <= 0)
{
freecnt++;
if((freecnt >= 20) && (CalculateTimeMsFromTick(CurrentTicksGain()) - heart_time >= HEART_TIME)) //连续20次未收到数据默认为为空闲状态,需每隔一段时间发送需要发送心跳包保活
{
heart_time = CalculateTimeMsFromTick(CurrentTicksGain());
freecnt = 0;
if(!MQTT_SendHeart()) //发送心跳包失败可能连接断开,需要重连
{
KPrintf("The connection has been disconnected, reconnecting!\n");
goto reconnect;
}
KPrintf("Send heartbeat packet successful!\n");
}
}
else if(MqttRxbuf[0] == 0x30)
{
freecnt = 0;
MQTT_DealPublishData(MqttRxbuf, datalen);
// 1.获取新版本固件大小及版本信息
ptr1 = strstr((char *)Platform_mqtt.cmdbuff,topicdatabuff[0]);
ptr2 = strstr((char *)Platform_mqtt.cmdbuff,"{\"code\":\"1000\"");
if((ptr1 != NULL) &&(ptr2 != NULL))
{
if(sscanf(ptr2,"{\"code\":\"1000\",\"data\":{\"size\":%d,\"streamId\":%d,\"sign\":\"%*32s\",\"dProtocol\":\"mqtt\",\"version\":\"%11s\"",&platform_ota.size,&platform_ota.streamId,platform_ota.version)==3)
{
KPrintf("OTA firmware information:file size is %d,file id is %d,file version is %s!\r\n",platform_ota.size,platform_ota.streamId,platform_ota.version);
KPrintf("------Start the firmware file transfer!------\r\n");
KPrintf("---------------------------------------------\r\n");
if(platform_ota.size > APP_FLASH_SIZE)
{
KPrintf("File size is larger than partition size,the partition size is %dk.\n",APP_FLASH_SIZE/1024);
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "File size is larger than partition size!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,platform_ota.size) != kStatus_Success)
{
KPrintf("Failed to erase download partition!\n");
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to erase download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
platform_ota.counter = (platform_ota.size%FRAME_LEN != 0)? (platform_ota.size/FRAME_LEN + 1):(platform_ota.size/FRAME_LEN);
platform_ota.num = 1; //下载次数,初始值为1
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else
{
KPrintf("Failed to get ota information!\n");
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "Failed to get ota information!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
break;
}
}
// 2.分片接收新版本固件
if(strstr((char *)Platform_mqtt.cmdbuff,topicdatabuff[1]))
{
memset(FrameBuf,0,sizeof(FrameBuf));
memcpy(FrameBuf, &MqttRxbuf[datalen-platform_ota.downlen-2], platform_ota.downlen);
if(mcuboot.op_flash_write(flashdestination,FrameBuf,platform_ota.downlen) != kStatus_Success)
{
KPrintf("current frame[%d] flash failed.\n",platform_ota.num-1);
ret = -1;
ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
sprintf(ota_info.error_message,"current frame[%d] flash failed.",platform_ota.num-1);
UpdateOTAFlag(&ota_info);
break;
}
else
{
displayProgress((platform_ota.num*100)/platform_ota.counter);
flashdestination += platform_ota.downlen;
platform_ota.num++;
}
if(platform_ota.num < platform_ota.counter) //如果小于总下载次数
{
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else if(platform_ota.num == platform_ota.counter) //如果等于总下载次数,说明是最后一次下载
{
if(platform_ota.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍
{
platform_ota.downlen = FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
else
{
platform_ota.downlen = platform_ota.size%FRAME_LEN; //记录本次下载量
OTA_Download(platform_ota.downlen,(platform_ota.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器
}
}
else //下载完毕
{
ret = 0;
break;
}
}
}
else
{
freecnt = 0;
continue;
}
}
// 新版本固件接收完毕,写入描述信息
if(0 == ret)
{
ota_info.down.size = platform_ota.size;
ota_info.down.crc32 = calculate_crc32(DOWN_FLAH_ADDRESS, platform_ota.size);
memset(ota_info.down.version,0,sizeof(ota_info.down.version));
strncpy(ota_info.down.version, platform_ota.version, sizeof(ota_info.down.version));
memset(ota_info.down.description,0,sizeof(ota_info.down.description));
strncpy(ota_info.down.description, "MQTT OTA bin.",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
KPrintf("firmware file transfer successful,start reboot!\n");
}
else
{
KPrintf("firmware file transfer failed,start reboot!\n");
}
MQTT_Disconnect();
mcuboot.flash_deinit();
MdelayKTask(2000);
mcuboot.op_reset();
}
#endif
int OtaTask(void)
{
int32 ota_task = 0;
ota_task = KTaskCreate("mqtt_platform", mqttCloudInteraction, NULL,10240, 10);
if(ota_task < 0) {
KPrintf("matt platform task create failed ...%s %d.\n", __FUNCTION__,__LINE__);
return ERROR;
}
StartupKTask(ota_task);
return 0;
}
#endif
/*******************************************************************************
* 函 数 名: app_clear_jumpflag
* 功能描述: 跳转app成功后,在app中调用将lastjumpflag重置为0XCDCDCDCD
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
void app_clear_jumpflag(void)
{
ota_info_t ota_info;
mcuboot.flash_init();
//跳转成功设置lastjumpflag为JUMP_SUCCESS_FLAG
memset(&ota_info, 0, sizeof(ota_info_t));
mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t));
ota_info.lastjumpflag = JUMP_SUCCESS_FLAG;
UpdateOTAFlag(&ota_info);
mcuboot.flash_deinit();
}
/*******************************************************************************
* 函 数 名: ota_entry
* 功能描述: bootloader的入口函数
* 形 参: 无
* 返 回 值: 无
*******************************************************************************/
void ota_entry(void)
{
uint8_t ch1, ch2;
uint32_t ret;
uint32_t timeout = 1000;
mcuboot.board_init();
mcuboot.print_string("Please press 'space' key into menu in 5s !!!\r\n");
while(timeout)
{
ret = (SerialKeyPressed((uint8_t*)&ch1));
if(ret) break;
timeout--;
mcuboot.op_delay(5);
}
while(1)
{
if((ret)&&(ch1 == 0x20))
{
mcuboot.print_string("\r\nPlease slecet:");
mcuboot.print_string("\r\n 1:run app");
mcuboot.print_string("\r\n 2:update app");
mcuboot.print_string("\r\n 3:reboot \r\n");
ch2 = GetKey();
switch(ch2)
{
case 0x31:
BootLoaderJumpApp();
break;
case 0x32:
Update();
BootLoaderJumpApp();
break;
case 0x33:
mcuboot.op_reset();
default:
break;
}
}
//10s内不按下空格键默然进行升级,升级完成后跳转
else
{
Update();
BootLoaderJumpApp();
}
}
}