diff --git a/APP_Framework/Applications/ota/Kconfig b/APP_Framework/Applications/ota/Kconfig old mode 100755 new mode 100644 index 097519d9b..e69de29bb --- a/APP_Framework/Applications/ota/Kconfig +++ b/APP_Framework/Applications/ota/Kconfig @@ -1,7 +0,0 @@ -menu "ota app " - menuconfig APPLICATION_OTA - bool "Using app bin ota" - default n - - -endmenu diff --git a/APP_Framework/Applications/ota/Makefile b/APP_Framework/Applications/ota/Makefile index 2f5316c0d..47afc2d36 100644 --- a/APP_Framework/Applications/ota/Makefile +++ b/APP_Framework/Applications/ota/Makefile @@ -1,3 +1,3 @@ SRC_FILES := ota.c -include $(KERNEL_ROOT)/compiler.mk +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/APP_Framework/Applications/ota/README.md b/APP_Framework/Applications/ota/README.md deleted file mode 100644 index a8243454a..000000000 --- a/APP_Framework/Applications/ota/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# OTA README - -xiuos当前的ota功能允许应用bin文件可以通过4G实现远程的bin文件更新(限制:1、bin文件存放在设备SD卡并且应用从SD卡启动;2、暂且支持4G实现;3、暂时只支持aiit终端;4、只支持xiuos内核)。 - -## 文件说明 - -| 名称 | 说明 | -| -- | -- | -| ota.c| xiuos设备OTA代码 | -| ota_server.c | pc服务端的实例代码供参考 | - - -## 使用说明 -xiuos的应用bin文件更新依赖上层的adapter框架,因此需要在menuconfig同时配置以下选项: -1、ota开关APPLICATION_OTA打开; -2、adapter的4G功能开关; -3、拆分的应用启动SEPARATE_COMPILE开关从SD卡启动的配置开关APP_STARTUP_FROM_SDCARD。 - - diff --git a/APP_Framework/Applications/ota/ota.c b/APP_Framework/Applications/ota/ota.c index d361a0f78..e132346e3 100644 --- a/APP_Framework/Applications/ota/ota.c +++ b/APP_Framework/Applications/ota/ota.c @@ -1,4 +1,3 @@ - /* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. @@ -13,399 +12,1047 @@ /** * @file: ota.c -* @brief: a application ota task of system +* @brief: file ota.c * @version: 1.0 * @author: AIIT XUOS Lab -* @date: 2021/11/3 +* @date: 2023/4/23 * */ +#include #include +#include "shell.h" +#include "xsconfig.h" +#include "mcuboot.h" +#include "ymodem.h" +#include "ota.h" + +#ifdef CONNECTION_ADAPTER_4G #include +#endif -extern int main(void); +#ifdef OTA_BY_PLATFORM +#include "platform_mqtt.h" +#endif -struct ota_header_t +/**************************************************************************** + * 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 void UpdateNewApplication(void); +static void Update(void); +static void BootLoaderJumpApp(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static const mcuboot_t mcuboot = { - int16 frame_flag; ///< frame start flag 2 Bytes - uint8 dev_type; ///< device type - uint8 burn_mode; ///< data burn way - uint32 total_len; ///< send data total length caculated from each frame_len - uint32 dev_hid; ///< device hardware version - uint32 dev_sid; ///< device software version - char resv[8]; ///< reserve + 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 }; -struct ota_frame_t + +/******************************************************************************* +* 函 数 名: calculate_crc32 +* 功能描述: 计算给定Flash内存地址范围中数据的CRC32校验和 +* 形 参: addr:表示Flash地址的起始位置 + len:表示需要计算CRC32的数据长度 +* 返 回 值: 计算得到的CRC32值 +*******************************************************************************/ +static uint32_t calculate_crc32(uint32_t addr, uint32_t len) { - uint32 frame_id; ///< Current frame id - uint32 frame_len; ///< Current frame data length - char frame_data[64]; ///< Current frame data,max length 64 - uint32 crc; ///< Current frame data crc -}; + uint32_t crc = 0xFFFFFFFF; + uint8_t byte = 0xFF; -struct ota_data + 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,如01.02.03 +*******************************************************************************/ +static int create_version(uint8_t* cur_version, uint8_t* new_version) { - struct ota_header_t header; - struct ota_frame_t frame; - char end[4]; -}; + int major, minor, patch; //三段式版本号的各个部分 -pthread_t ota_task; -pthread_t restart_main; + //解析当前版本号,版本号格式不对直接返回 + if (sscanf(cur_version, "%03d.%03d.%03d", &major, &minor, &patch) != 3) { + return -1; + } -/** - * @description: CRC16 check - * @param data data buffer - * @param length data length - * @return check code - */ -uint32_t OtaCrc16(uint8_t * data, uint32_t length) + //将当前版本号加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) { - int j; - unsigned int reg_crc=0xFFFF; - printf("crc data length[%d] Bytes,",length); + status_t status; - while (length--) { + 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); + status = mcuboot.op_flash_copy(BAKUP_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.bak.size); + if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.bak.size) == ota_info.bak.crc32)) + { + mcuboot.print_string("\r\n------Backup app version success!------\r\n"); + 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); + } + else + { + mcuboot.print_string("\r\n------Backup app version failed!------\r\n"); + ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); + strncpy(ota_info.error_message, "Backup app version failed!",sizeof(ota_info.error_message)); + + UpdateOTAFlag(&ota_info); + } +} + + +/******************************************************************************* +* 函 数 名: UpdateNewApplication +* 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新 +* 形 参: 无 +* 返 回 值: 无 +* 注 释: 该函数调用后如果不需要升级APP分区保持不变,否则APP分区的版本为新版本 +*******************************************************************************/ +static void 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 to update the app!------\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校验通过,开始升级,逐字节拷贝Flash,先备份当前XiUOS System分区内容 + 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)) + { + mcuboot.print_string("\r\n------Backup app success!------\r\n"); + 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);; + } + else + { + mcuboot.print_string("\r\n------Backup app failed!------\r\n"); + 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);; + goto finish; + } + + // 2.拷贝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)) + { + mcuboot.print_string("\r\n------The download partition is copied successfully!------\r\n"); + + 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)); + + ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE + UpdateOTAFlag(&ota_info);; + } + else + { + mcuboot.print_string("\r\n------The download partition copy failed!------\r\n"); + 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);; + goto finish; + } + + mcuboot.print_string("\r\n------Update completed!------\r\n"); + goto finish; + } + else + { + // 如果download分区CRC校验失败,升级失败 + mcuboot.print_string("\r\n------Download Firmware CRC check failed!------\r\n"); + 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);; + goto finish; + } + } + else + { + mcuboot.print_string("\r\n------No need to update the app!------\r\n"); + goto finish; + } +finish: + return; +} + + +/******************************************************************************* +* 函 数 名: 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下通过iap烧写出厂固件 */ + if((ota_info.os.size > APP_FLASH_SIZE) || (calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.os.size) != ota_info.os.crc32)) + { + mcuboot.print_string("\r\nNeed to flash initial firmware!\r\n"); + InitialVersion(); + } + else + { + UpdateNewApplication(); + } + 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------Bootloader false, begin backup!------\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(); + 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 (j=0;j<8;j++) { + for(int j=0;j<8;j++) + { if(reg_crc & 0x01) reg_crc=reg_crc >>1 ^ 0xA001; else reg_crc=reg_crc >>1; } } - printf(" crc = [0x%x]\n",reg_crc); + KPrintf("crc = [0x%x]\n",reg_crc); return reg_crc; } -uint32_t FileCrc16(uint8_t * data, uint32_t length, unsigned int last_crc) + +/******************************************************************************* +* 函 数 名: get_start_signal +* 功能描述: 通过4G方式从服务端接收开始信号 +* 形 参: adapter:Adapter指针,指向注册的4G设备 +* 返 回 值: 0:传输成功,-1:传输失败 +*******************************************************************************/ +static void get_start_signal(struct Adapter* adapter) { - int j; - //printf("crc data length[%d] Bytes,",length); - - while (length--) { - last_crc ^= *data++; - for (j=0;j<8;j++) { - if(last_crc & 0x01) - last_crc = last_crc >>1 ^ 0xA001; - else - last_crc = last_crc >>1; - } - } + ota_info_t ota_info; + uint8_t reply[16] = {0}; + uint32_t flashdestination = DOWN_FLAH_ADDRESS; - //printf(" crc = [0x%x]\n",last_crc); - - return last_crc; -} - - -static int SaveAppBin(int fd, char* buf, int len) -{ - int ret = 0; - int fd_t = 0; - fd_t = open( BOARD_APP_NAME, O_RDWR | O_APPEND); - ret = write(fd, buf, len); - if(ret < 0){ - printf("fd = %d write buf len[%d] failed.ret = %d\n",fd_t,len,ret); - } - else + 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) { - printf("fd[%d] write buf length[%d] done.\n",fd_t,ret); - } - - close(fd_t); -} - -static int CrcFileCheck(uint32 crc_check, unsigned long total_len) -{ - int ret = 0; - int fd = 0; - int len = 0; - char *buf = NULL; - unsigned int last_crc = 0xffff; - unsigned long already_crc_length = 0; - - fd = open( BOARD_APP_NAME, O_RDONLY ); - if(fd < 0){ - printf("open %s bin failed.\n",BOARD_APP_NAME); - return -1; - } - - buf = PrivMalloc(128); - if(NULL == buf) - { - printf("malloc failed.\n"); - close(fd); - return 0; - } - - /* crc check every 1024 Bytes until crc all the total file */ - while(already_crc_length != total_len) - { - memset(buf , 0 , 128); - len = read(fd, buf, 128); - if(len < 0) + 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) { - printf("file read failed.ret = %d\n",len); - ret = -1; - break; - } - - last_crc = FileCrc16(buf, len, last_crc); - already_crc_length += len; - printf("read len[%d] Bytes,already_crc_length[%d]\n",len,already_crc_length); - } - - - if (last_crc != crc_check) - { - printf("file crc error!!! last crc[%x] != check[%x]\n",last_crc,crc_check); - ret =-1; - } - - PrivFree(buf); - close(fd); - - return ret; -} - -static void RestartApplication(void) -{ - pthread_attr_t attr; - attr.schedparam.sched_priority = 10; - attr.stacksize = 2048; - - while(1) - { - unsigned long pid = PrivUserTaskSearch(); - if ((pid > 0) && (pid != pthread_self())) - { - printf("kill usertask pid[%d]\n",pid); - PrivTaskDelete(pid, 0); - PrivTaskDelay(1000); /* NOTE:this delay will make a schedule and recycle all user task */ - } - else - { - break; - } - } - printf("restart main.\n"); - PrivTaskCreate(&restart_main, &attr, (void *)main, NULL); -} -static int OtaDataRecv(struct Adapter* adapter) -{ - struct ota_data recv_msg; - char reply[16] = {0}; - int ret = 0; - int try_times = 10; - int fd = 0; - int frame_cnt = 0; - - fd = open( BOARD_APP_NAME, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if(fd < 0) - { - printf("open %s failed\n",BOARD_APP_NAME); - return -1; - } - close(fd); - - while(1) { - memset(&recv_msg, 0, sizeof(struct ota_data)); - printf("recv msg...\n"); - ret = AdapterDeviceRecv(adapter, &recv_msg, sizeof(struct ota_data)); - if(ret >= 0 && recv_msg.header.frame_flag == 0x5A5A) - { - if(0 == strncmp("aiit_ota_end",recv_msg.frame.frame_data, strlen("aiit_ota_end"))) + if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,start_msg.header.total_len) != kStatus_Success) { - printf("total [%d]frames [%d]Bytes crc[%x],receive successful,\n",frame_cnt,recv_msg.header.total_len,recv_msg.frame.crc); - if(0 != CrcFileCheck(recv_msg.frame.crc, recv_msg.header.total_len)) - { - printf("crc check %s bin failed.please try again.\n", BOARD_APP_NAME); - ret = -1; - break; - } - PrivTaskDelay(500); - printf("tolal file crc done.send ok\n"); - memset(reply, 0, 16); - memcpy(reply, "ok", strlen("ok")); + 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; } - frame_cnt = recv_msg.frame.frame_id; - - if(0 == strncmp("wait_ok_timeout",recv_msg.frame.frame_data, strlen("wait_ok_timeout"))) + else //说明当前接收的数据帧不是上述三种数据帧的任意一种 { - printf("go to send ok again.\n"); - goto send_ok_again; - - } - - if (recv_msg.frame.crc == OtaCrc16(recv_msg.frame.frame_data,recv_msg.frame.frame_len)) - { - printf("save current [%d] frame,length[%d] Bytes.\n",frame_cnt,recv_msg.frame.frame_len); - for(int i = 0; i < recv_msg.frame.frame_len;i++ ){ - printf(" %x ",*((char *)&recv_msg.frame.frame_data + i)); - } - printf("\n"); - SaveAppBin(fd, recv_msg.frame.frame_data, recv_msg.frame.frame_len); - } - else - { - printf("current [%d] frame crc check failed,try again!\n",frame_cnt); goto try_again; } send_ok_again: - memset(reply, 0, 16); + memset(reply, 0, sizeof(reply)); memcpy(reply, "ok", strlen("ok")); - // PrivTaskDelay(100); ret = AdapterDeviceSend(adapter, reply, strlen(reply)); - if(ret < 0){ - printf("send ok failed.\n"); + if(ret < 0) + { + KPrintf("send ok failed.\n"); goto send_ok_again; } - printf("send reply[%s] done.\n",reply); - try_times = 10; + KPrintf("send reply[%s] done.\n",reply); + //send ok后把try_times重置为5 + try_times = 5; continue; - } + } + + //没有接收到数据或者接收到的数据帧不满足条件,需要发个retry的命令告诉服务器需要重传 else { try_again: if(try_times == 0) { - printf("oops!!! current [%d] frame try 10 times failed,break out!\n",frame_cnt); + KPrintf("current frame[%d] try 5 times failed,break out!\n",frame_cnt); ret = -1; break; } - memset(reply, 0, 16); + memset(reply, 0, sizeof(reply)); memcpy(reply, "retry", strlen("retry")); - printf("[%d] frame receive failed. retry\n",frame_cnt); + KPrintf("current frame[%d] receive failed. retry\n",frame_cnt); AdapterDeviceSend(adapter, reply, strlen(reply)); try_times--; continue; } } - close(fd); - if(0 == ret) { - printf("ota file done,start application.\n"); - RestartApplication(); + //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; } -static void *OtaKTaskEntry(void *parameter) + +/******************************************************************************* +* 函 数 名: app_ota_by_4g +* 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过4g方式传输bin文件 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +static void app_ota_by_4g(void) { - struct ota_data recv_msg; - char reply[16] = {0}; - int baud_rate = BAUD_RATE_115200; - int len = 0; - int ret = 0; + uint32_t baud_rate = BAUD_RATE_115200; + uint8_t server_addr[16] = "115.238.53.60"; + uint8_t server_port[8] = "7777"; - struct Adapter* adapter = AdapterDeviceFindByName("4G"); - uint8 server_addr[64] = "115.238.53.61"; - uint8 server_port[64] = "9898"; + 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); - - /* using nbiot as connection way*/ - -// struct Adapter* adapter = AdapterDeviceFindByName("nbiot"); - -// while(1) -// { -// int connect_times = 5; -// ret = AdapterDeviceOpen(adapter); -// if(ret < 0) -// { -// printf("open adapter failed\n"); -// continue; -// } - -// connect_again: -// connect_times--; -// ret = AdapterDeviceConnect(adapter, 1, "115.238.53.61","9898",1); -// if(ret < 0) -// { -// if(connect_times > 0){ -// goto connect_again; -// } -// else -// { -// AdapterDeviceClose(adapter); -// continue; -// } -// } -// break; -// } - PrivTaskDelay(5000); + MdelayKTask(100); while(1) { - memset(&recv_msg, 0, sizeof(struct ota_data)); - /* step1: Confirm the start signal of transmission*/ - printf("waiting for start msg...\n"); - ret = AdapterDeviceRecv(adapter, &recv_msg, sizeof(struct ota_data)); - for(int i = 0; i < sizeof(struct ota_data);i++ ){ - printf(" %x ",*((char *)&recv_msg + i)); - } - printf("\n"); - if(ret >= 0 && recv_msg.header.frame_flag == 0x5A5A) + /* 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)) { - if (0 == strncmp("aiit_ota_start",recv_msg.frame.frame_data, strlen("aiit_ota_start"))) + break; + } + } + mcuboot.flash_deinit(); + KPrintf("ota file transfer complete,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 +#define FRAME_LEN 2048 //每帧数据的数据包长度 +static uint8_t MqttRxbuf[3072]; +static uint8_t FrameBuf[FRAME_LEN]; +static OTA_TCB AliOTA; + +/******************************************************************************* +* 函 数 名: 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); + + MQTT_PublishDataQs1(topicdatabuff,tempdatabuff,strlen(tempdatabuff)); //发送等级QS=1的PUBLISH报文 +} + + +/*-------------------------------------------------*/ +/*函数名:OTA下载数据 */ +/*参 数:size:本次下载量 */ +/*参 数:offset:本次下载偏移量 */ +/*返回值:无 */ +/*-------------------------------------------------*/ +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}}}",AliOTA.streamId,size,offset); + + MQTT_PublishDataQs0(topicdatabuff, tempdatabuff, strlen(tempdatabuff)); +} + +/******************************************************************************* +* 函 数 名: app_ota_by_platform +* 功能描述: 通过云平台MQTT进行升级 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +static void app_ota_by_platform(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[64]; + char *ptr; + + 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,64); + sprintf(topicdatabuff,"/sys/%s/%s/thing/file/download_reply",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME); + +reconnect: + if((AdapterNetActive() == 0) && (MQTT_Connect() == 0) && MQTT_SubscribeTopic(topicdatabuff) == 0) + { + 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++; + } + else if(MqttRxbuf[0] == 0x30) + { + freecnt = 0; + MQTT_DealPublishData(MqttRxbuf, datalen); + ptr = strstr((char *)Platform_mqtt.cmdbuff,"{\"code\":\"1000\""); + if(ptr != NULL) { - memset(reply, 0, 16); - memcpy(reply, "ready", strlen("ready")); - // PrivTaskDelay(3000); - printf("receive start signal,send [ready] signal to server\n"); -send_ready_again: - ret = AdapterDeviceSend(adapter, reply, strlen(reply)); - if(ret < 0) + if(sscanf(ptr,"{\"code\":\"1000\",\"data\":{\"size\":%d,\"streamId\":%d,\"sign\":\"%*32s\",\"dProtocol\":\"mqtt\",\"version\":\"%11s\"",&AliOTA.size,&AliOTA.streamId,AliOTA.version)==3) { - goto send_ready_again; + KPrintf("ota file size:%d\r\n",AliOTA.size); + KPrintf("ota file id:%d\r\n",AliOTA.streamId); + KPrintf("ota file version:%s\r\n",AliOTA.version); + if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,AliOTA.size != kStatus_Success)) + { + KPrintf("Failed to erase target fash!\n"); + ret = -1; + break; + } + AliOTA.counter = (AliOTA.size%FRAME_LEN != 0)? (AliOTA.size/FRAME_LEN + 1):(AliOTA.size/FRAME_LEN); + AliOTA.num = 1; //下载次数,初始值为1 + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 } - PrivTaskDelay(3000); - printf("start receive ota file.\n"); - /* step2: start receive source bin file of application*/ - ret = OtaDataRecv(adapter); - if (0 != ret) - { - memset(reply, 0, 16); - memcpy(reply, "ota_restart", strlen("ota_restart")); - AdapterDeviceSend(adapter, reply, strlen(reply)); - continue; - } else { + KPrintf("Failed to get ota information!\n"); + ret = -1; + break; + } + } + + if(strstr((char *)Platform_mqtt.cmdbuff,"download_reply")) + { + memset(FrameBuf,0,sizeof(FrameBuf)); + memcpy(FrameBuf, &MqttRxbuf[datalen-AliOTA.downlen-2], AliOTA.downlen); + if(mcuboot.op_flash_write(flashdestination,FrameBuf,AliOTA.downlen) != kStatus_Success) + { + KPrintf("current frame[%d] flash failed.\n",AliOTA.num-1); + ret = -1; + break; + } + else + { + KPrintf("current frame[%d] is written to flash 0x%x address successful.\n", AliOTA.num -1, flashdestination); + KPrintf("Current progress is %d/%d\r\n",AliOTA.num,AliOTA.counter); + flashdestination += AliOTA.downlen; + AliOTA.num++; + } + + if(AliOTA.num < AliOTA.counter) //如果小于总下载次数 + { + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + else if(AliOTA.num == AliOTA.counter) //如果等于总下载次数,说明是最后一次下载 + { + if(AliOTA.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍 + { + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + else + { + AliOTA.downlen = AliOTA.size%FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + } + + else //下载完毕 + { + ret = 0; break; } } + } else { - memset(reply, 0, 16); - memcpy(reply, "notready", strlen("notready")); - printf("ota status:not ready\n"); - ret = AdapterDeviceSend(adapter, reply, strlen(reply)); + freecnt = 0; + continue; + } + + if((freecnt >= 10) && (CalculateTimeMsFromTick(CurrentTicksGain()) - heart_time >= HEART_TIME)) //连续10次未收到数据默认为为空闲状态,需每隔一段时间发送需要发送心跳包保活 + { + heart_time = CalculateTimeMsFromTick(CurrentTicksGain()); + if(MQTT_SendHeart() != 0) //发送心跳包失败可能连接断开,需要重连 + { + KPrintf("The connection has been disconnected, reconnecting!\n"); + freecnt = 0; + heart_time = 0; + goto reconnect; + } + KPrintf("Send heartbeat packet successful!\n"); } - PrivTaskDelay(3000); /* check ota signal every 5s */ } - AdapterDeviceClose(adapter); + + if(0 == ret) + { + ota_info.down.size = AliOTA.size; + ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, AliOTA.size); + + memset(ota_info.down.version,0,sizeof(ota_info.down.version)); + strncpy(ota_info.down.version, AliOTA.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); + } + 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); + } + MQTT_UnSubscribeTopic(topicdatabuff); + MQTT_Disconnect(); + mcuboot.flash_deinit(); + KPrintf("ota file transfer complete,start reboot!\n"); + MdelayKTask(2000); + mcuboot.op_reset(); } -void ApplicationOtaTaskInit(void) -{ - pthread_attr_t attr; - attr.schedparam.sched_priority = 20; - attr.stacksize = 4096; +int OtaTask(void) +{ + int32 ota_task = 0; + ota_task = KTaskCreate("ota_platform", app_ota_by_platform, NULL,8192, 10); + if(ota_task < 0) { + KPrintf("ota_task create failed ...%s %d.\n", __FUNCTION__,__LINE__); + return ERROR; + } - PrivTaskCreate(&ota_task, &attr, OtaKTaskEntry, NULL); + 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 10s !!!\r\n"); + + while(timeout) + { + ret = (SerialKeyPressed((uint8_t*)&ch1)); + if(ret) break; + timeout--; + mcuboot.op_delay(10); + } + + 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(); + } + } } \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h b/APP_Framework/Applications/ota/ota.h similarity index 100% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h rename to APP_Framework/Applications/ota/ota.h diff --git a/APP_Framework/Applications/ota/ota_server.c b/APP_Framework/Applications/ota/ota_server.c deleted file mode 100644 index 335b0a226..000000000 --- a/APP_Framework/Applications/ota/ota_server.c +++ /dev/null @@ -1,385 +0,0 @@ -/* -* 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_server.c -* @brief: a application ota task of system running in Linux -* @version: 1.0 -* @author: AIIT XUOS Lab -* @date: 2021/11/3 -* -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -typedef int BOOL; -#define true 1 -#define false 0 - -int serverfd;//服务器socket -int clientfd[100000];//客户端的socketfd,100个元素,clientfd[0]~clientfd[99] -int size = 99999;//用来控制进入聊天室的人数为50以内 -int PORT = 9898;//端口号 -typedef struct sockaddr meng; - -struct ota_header_t -{ - int16_t frame_flag; ///< frame start flag 2 Bytes - uint8_t dev_type; ///< device type - uint8_t burn_mode; ///< data burn way - uint32_t total_len; ///< send data total length caculated from each frame_len - uint32_t dev_hid; ///< device hardware version - uint32_t dev_sid; ///< device software version - char resv[8]; ///< reserve -}; - -struct ota_frame_t -{ - uint32_t frame_id; ///< Current frame id - uint32_t frame_len; ///< Current frame data length - char frame_data[64]; ///< Current frame data,max length 224 - uint32_t crc; ///< Current frame data crc -}; - -struct ota_data -{ - struct ota_header_t header; - struct ota_frame_t frame; - char end[4]; -}; - -pthread_t ota_ktask; - -/** - * @description: CRC16 check - * @param data data buffer - * @param length data length - * @return check code - */ -uint32_t OtaCrc16(uint8_t * data, uint32_t length) -{ - int j; - unsigned int reg_crc=0xFFFF; - - printf("crc data length[%d] Bytes,",length); - - while (length--) { - reg_crc ^= *data++; - for (j=0;j<8;j++) { - if(reg_crc & 0x01) - reg_crc=reg_crc >>1 ^ 0xA001; - else - reg_crc=reg_crc >>1; - } - } - printf(" crc = [0x%x]\n",reg_crc); - return reg_crc; -} - -void init(void) -{ - serverfd = socket(PF_INET,SOCK_STREAM,0); - - if (serverfd == -1) - { - perror("创建socket失败"); - exit(-1); - } - -//为套接字设置ip协议 设置端口号 并自动获取本机ip转化为网络ip - - struct sockaddr_in addr;//存储套接字的信息 - addr.sin_family = AF_INET;//地址族 - addr.sin_port = htons(PORT);//设置server端端口号,你可以随便设置,当sin_port = 0时,系统随机选择一个未被使用的端口号 - addr.sin_addr.s_addr = htons(INADDR_ANY);//当sin_addr = INADDR_ANY时,表示从本机的任一网卡接收数据 - -//绑定套接字 - // int on = 1; - struct timeval timeout; - timeout.tv_sec = 5; - timeout.tv_usec = 0; - if(setsockopt(serverfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) - { - perror("端口设置失败"); - exit(-1); - } - - if (bind(serverfd,(meng*)&addr,sizeof(addr)) == -1) - { - perror("绑定失败"); - exit(-1); - } - - if (listen(serverfd,100) == -1) - {//监听最大连接数 - perror("设置监听失败"); - exit(-1); - } -} -int OtaFileSend(int fd) -{ - unsigned char buf[32] = { 0 }; - struct ota_data data; - FILE *file_fd; - char ch; - int length = 0; - int try_times = 10; - int recv_end_times = 3; - int ret = 0; - int frame_cnt = 0; - int file_length = 0; - char * file_buf = NULL; - - file_fd = fopen("/home/aep04/wwg/XiUOS_aiit-arm32-board_app.bin", "r"); - if (NULL == file_fd){ - printf("open file failed.\n"); - return -1; - } - fseek(file_fd, 0, SEEK_SET); - printf("start send file.\n"); - while(!feof(file_fd)) - { - memset(&data, 0, sizeof(data)); - - data.header.frame_flag = 0x5A5A; - length = fread( data.frame.frame_data, 1, 64, file_fd ); - if(length > 0) - { - printf("read %d Bytes\n",length); - data.frame.frame_id = frame_cnt; - data.frame.frame_len = length; - data.frame.crc = OtaCrc16(data.frame.frame_data, length); - file_length += length; - } - -send_again: - usleep(50000); - printf("ota send current[%d] frame.\n",frame_cnt); - length = send(fd, &data, sizeof(data), MSG_NOSIGNAL); - if(length < 0){ - printf("send [%d] frame faile.go to send again\n",frame_cnt); - goto send_again; - } - -recv_again: - memset(buf, 0, 32); - length = recv(fd, buf, sizeof(buf), 0); - if(length < 0 ){ - printf("[%d] frame waiting for ok timeout,receive again.\n",frame_cnt); - goto recv_again; - } - - printf("receive buf[%s] length = %d\n",buf, length); - if(0 == strncmp(buf, "ok", length)) - { - try_times = 10; - printf("[%d]frame data send done.\n",frame_cnt); - frame_cnt++; - continue; - } - else - { - if(try_times > 0) - { - try_times--; - goto send_again; - } - else - { - printf("send frame[%d] 10 times failed.\n",frame_cnt); - ret = -1; - break; - } - } - } - - /* finally,crc check total bin file.*/ - if (ret == 0) - { - sleep(1); - printf("total send file length[%d] Bytes [%d] frames.\n",file_length,frame_cnt); - printf("now crc check total bin file.\n"); - file_buf = malloc(file_length); - memset(file_buf, 0, file_length); - memset(&data, 0, sizeof(data)); - - data.header.frame_flag = 0x5A5A; - - file_fd = fopen("/home/aep04/wwg/XiUOS_aiit-arm32-board_app.bin", "r"); - if (NULL == file_fd){ - printf("open file failed.\n"); - return -1; - } - fseek(file_fd, 0, SEEK_SET); - length = fread(file_buf,1, file_length, file_fd); - printf("read file length = %d\n",length); - if(length > 0) { - data.frame.frame_id = frame_cnt; - data.header.total_len = file_length; - data.frame.frame_len = strlen("aiit_ota_end"); - data.frame.crc = OtaCrc16(file_buf, length); - memcpy(data.frame.frame_data,"aiit_ota_end",strlen("aiit_ota_end")); - } - -send_end_signal: - printf("send aiit_ota_end signal.\n"); - length = send(fd, &data, sizeof(data), MSG_NOSIGNAL); - if(length < 0){ - printf("send end signal faile,send end signal again\n"); - goto send_end_signal; - } - -recv_end_signal: - memset(buf, 0, 32); - length = recv(fd, buf, sizeof(buf), 0); - if(length < 0 ) - { - recv_end_times--; - printf("end signal waiting for ok timeout,receive again.\n"); - if(recv_end_times > 0) - { - goto recv_end_signal; - } - else - { - ret = -1; - } - } - - if(0 != strncmp(buf, "ok", length)) - { - printf("error end !!!\n"); - ret = -1; - } - - free(file_buf); - } - - fclose(file_fd); - return ret; -} - -void* server_thread(void* p) -{ - int fd = *(int*)p; - unsigned char buf[32] = { 0 }; - struct ota_data data; - int ret = 0; - int length = 0; - - printf("pthread = %d\n",fd); - sleep(8); - while(1) - { - memset(&data, 0x0 , sizeof(struct ota_data)); - data.header.frame_flag = 0x5A5A; - memcpy(data.frame.frame_data,"aiit_ota_start",strlen("aiit_ota_start")); - data.frame.frame_len = strlen("aiit_ota_start"); - - printf("send start signal.\n"); - ret = send(fd, &data, sizeof(data), MSG_NOSIGNAL); - if (ret > 0){ - printf("send %s[%d] Bytes\n",data.frame.frame_data,ret); - } - // sleep(1); - memset(buf, 0, 32); - length = recv(fd, buf, sizeof(buf), 0); - if (length <= 0) - { - continue; - } - else - { - printf("recv buf %s length %d\n",buf,length); - if(0 == strncmp(buf, "ready", length)) - { - ret = OtaFileSend(fd); - if (ret == 0) { - printf("ota file send successful.\n"); - break; - } else { /* ota failed then restart the ota process */ - continue; - } - } - } - } - printf("exit fd = %d\n",fd); - close(fd); - pthread_exit(0); -} - -void server(void) -{ - printf("ota Server startup\n"); - while(1) - { - struct sockaddr_in fromaddr; - socklen_t len = sizeof(fromaddr); - int fd = accept(serverfd,(meng*)&fromaddr,&len); - -//调用accept进入堵塞状态,等待客户端的连接 - - if (fd == -1) - { - // printf("The client connection is wrong...\n"); - continue; - } - - int i = 0; - for (i = 0;i < size;i++) - { - if (clientfd[i] == 0) - { - //记录客户端的socket - clientfd[i] = fd; - - //有客户端连接之后,启动线程给此客户服务 - pthread_t tid; - pthread_create(&tid,0,server_thread,&fd); - break; - } - - if (size == i) - { - //发送给客户端说聊天室满了 - char* str = "Devices full"; - printf("%s", str); - send(fd,str,strlen(str),0); - close(fd); - } - } - } -} - -int main(void) -{ - init(); - server(); -} - diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/server_tcp.c b/APP_Framework/Applications/ota/server_tcp.c similarity index 100% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/ota/server_tcp.c rename to APP_Framework/Applications/ota/server_tcp.c diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/Kconfig similarity index 100% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/flash/Kconfig rename to Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/Kconfig diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/flash_ops.c b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/Makefile similarity index 100% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/flash/flash_ops.c rename to Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/Makefile diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/Kconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/boot_for_ota.c similarity index 100% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/ota/Kconfig rename to Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/boot_for_ota.c diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/third_party_driver/ota/flash_for_ota.c new file mode 100644 index 000000000..e69de29bb diff --git a/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/Kconfig b/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/Kconfig new file mode 100644 index 000000000..e69de29bb diff --git a/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/Makefile b/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/Makefile new file mode 100644 index 000000000..e69de29bb diff --git a/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/boot_for_ota.c b/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/boot_for_ota.c new file mode 100644 index 000000000..e69de29bb diff --git a/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/flash_for_ota.c b/Ubiquitous/XiZi_IIoT/board/xishutong-arm32/third_party_driver/ota/flash_for_ota.c new file mode 100644 index 000000000..e69de29bb diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig deleted file mode 100644 index c826295d4..000000000 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig +++ /dev/null @@ -1,75 +0,0 @@ -menu "OTA function" - - menuconfig TOOL_USING_OTA - bool "Enable support OTA function" - default n - - if TOOL_USING_OTA - choice - prompt "Compile bootloader bin or application bin." - default MCUBOOT_BOOTLOADER - - config MCUBOOT_BOOTLOADER - bool "Config as bootloader." - - config MCUBOOT_APPLICATION - bool "Config as application." - endchoice - - if MCUBOOT_APPLICATION - choice - prompt "The way of OTA firmware upgrade." - default OTA_BY_PLATFORM - - config OTA_BY_PLATFORM - bool "Through IoT management platform." - select TOOL_USING_MQTT - - config OTA_BY_TCPSERVER - bool "Through the public network TCP server." - select SUPPORT_CONNECTION_FRAMEWORK - select CONNECTION_ADAPTER_4G - endchoice - endif - - - menu "Flash area address and size configuration." - config CHIP_FLAH_BASE - hex "Flash base address of the chip." - default 0x60000000 - - config XIUOS_FLAH_ADDRESS - hex "Flash area address of the XiUOS system." - default 0x60100000 - - config BAKUP_FLAH_ADDRESS - hex "Flash area address of the backup firmware." - default 0x60300000 - - config DOWN_FLAH_ADDRESS - hex "Flash area address of the downloaded firmware." - default 0x60500000 - - config FLAG_FLAH_ADDRESS - hex "Flash area address of the OTA information." - default 0x60700000 - - config APP_FLASH_SIZE - hex "Application package size,the default size is limited to 1M." - default 0x00100000 - endmenu - - config OTA_RX_TIMEOUT - int "OTA receive data timeout(ms)." - default 600 if OTA_BY_PLATFORM - default 10000 if OTA_BY_TCPSERVER - default 10000 if MCUBOOT_BOOTLOADER - - config OTA_RX_BUFFERSIZE - int "OTA receive data buffer size." - default 3072 if OTA_BY_PLATFORM - default 2048 if OTA_BY_TCPSERVER - default 256 if MCUBOOT_BOOTLOADER - endif - -endmenu diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/Makefile b/Ubiquitous/XiZi_IIoT/tool/bootloader/Makefile deleted file mode 100644 index 3e0f3289d..000000000 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -SRC_DIR := -SRC_DIR += flash ota - -include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/flash_ops.h b/Ubiquitous/XiZi_IIoT/tool/bootloader/bootloader_ops.h similarity index 92% rename from Ubiquitous/XiZi_IIoT/tool/bootloader/flash/flash_ops.h rename to Ubiquitous/XiZi_IIoT/tool/bootloader/bootloader_ops.h index e75abcd2e..e1bd9a8c3 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/flash_ops.h +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/bootloader_ops.h @@ -6,14 +6,14 @@ */ /** -* @file flash_ops.h +* @file bootloader_ops.h * @brief support flash function * @version 2.0 * @author AIIT XUOS Lab * @date 2023-04-03 */ -#ifndef __FLASH_OPS_H__ -#define __FLASH_OPS_H__ +#ifndef __BOOTLOADER_OPS_H__ +#define __BOOTLOADER_OPS_H__ #include diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/Makefile b/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/Makefile deleted file mode 100644 index 123d7c8b0..000000000 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/flash/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -SRC_FILES := flash_ops.c - -include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/Makefile b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/Makefile deleted file mode 100644 index 47afc2d36..000000000 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -SRC_FILES := ota.c - -include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c deleted file mode 100644 index e132346e3..000000000 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* -* 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 -#include -#include "shell.h" -#include "xsconfig.h" -#include "mcuboot.h" -#include "ymodem.h" -#include "ota.h" - -#ifdef CONNECTION_ADAPTER_4G -#include -#endif - -#ifdef OTA_BY_PLATFORM -#include "platform_mqtt.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 void 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,如01.02.03 -*******************************************************************************/ -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); - status = mcuboot.op_flash_copy(BAKUP_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.bak.size); - if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.bak.size) == ota_info.bak.crc32)) - { - mcuboot.print_string("\r\n------Backup app version success!------\r\n"); - 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); - } - else - { - mcuboot.print_string("\r\n------Backup app version failed!------\r\n"); - ota_info.status = OTA_STATUS_ERROR; - - memset(ota_info.error_message,0,sizeof(ota_info.error_message)); - strncpy(ota_info.error_message, "Backup app version failed!",sizeof(ota_info.error_message)); - - UpdateOTAFlag(&ota_info); - } -} - - -/******************************************************************************* -* 函 数 名: UpdateNewApplication -* 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新 -* 形 参: 无 -* 返 回 值: 无 -* 注 释: 该函数调用后如果不需要升级APP分区保持不变,否则APP分区的版本为新版本 -*******************************************************************************/ -static void 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 to update the app!------\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校验通过,开始升级,逐字节拷贝Flash,先备份当前XiUOS System分区内容 - 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)) - { - mcuboot.print_string("\r\n------Backup app success!------\r\n"); - 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);; - } - else - { - mcuboot.print_string("\r\n------Backup app failed!------\r\n"); - 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);; - goto finish; - } - - // 2.拷贝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)) - { - mcuboot.print_string("\r\n------The download partition is copied successfully!------\r\n"); - - 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)); - - ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE - UpdateOTAFlag(&ota_info);; - } - else - { - mcuboot.print_string("\r\n------The download partition copy failed!------\r\n"); - 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);; - goto finish; - } - - mcuboot.print_string("\r\n------Update completed!------\r\n"); - goto finish; - } - else - { - // 如果download分区CRC校验失败,升级失败 - mcuboot.print_string("\r\n------Download Firmware CRC check failed!------\r\n"); - 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);; - goto finish; - } - } - else - { - mcuboot.print_string("\r\n------No need to update the app!------\r\n"); - goto finish; - } -finish: - return; -} - - -/******************************************************************************* -* 函 数 名: 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下通过iap烧写出厂固件 */ - if((ota_info.os.size > APP_FLASH_SIZE) || (calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.os.size) != ota_info.os.crc32)) - { - mcuboot.print_string("\r\nNeed to flash initial firmware!\r\n"); - InitialVersion(); - } - else - { - UpdateNewApplication(); - } - 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------Bootloader false, begin backup!------\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(); - 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(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("ota file transfer complete,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 -#define FRAME_LEN 2048 //每帧数据的数据包长度 -static uint8_t MqttRxbuf[3072]; -static uint8_t FrameBuf[FRAME_LEN]; -static OTA_TCB AliOTA; - -/******************************************************************************* -* 函 数 名: 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); - - MQTT_PublishDataQs1(topicdatabuff,tempdatabuff,strlen(tempdatabuff)); //发送等级QS=1的PUBLISH报文 -} - - -/*-------------------------------------------------*/ -/*函数名:OTA下载数据 */ -/*参 数:size:本次下载量 */ -/*参 数:offset:本次下载偏移量 */ -/*返回值:无 */ -/*-------------------------------------------------*/ -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}}}",AliOTA.streamId,size,offset); - - MQTT_PublishDataQs0(topicdatabuff, tempdatabuff, strlen(tempdatabuff)); -} - -/******************************************************************************* -* 函 数 名: app_ota_by_platform -* 功能描述: 通过云平台MQTT进行升级 -* 形 参: 无 -* 返 回 值: 无 -*******************************************************************************/ -static void app_ota_by_platform(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[64]; - char *ptr; - - 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,64); - sprintf(topicdatabuff,"/sys/%s/%s/thing/file/download_reply",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME); - -reconnect: - if((AdapterNetActive() == 0) && (MQTT_Connect() == 0) && MQTT_SubscribeTopic(topicdatabuff) == 0) - { - 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++; - } - else if(MqttRxbuf[0] == 0x30) - { - freecnt = 0; - MQTT_DealPublishData(MqttRxbuf, datalen); - ptr = strstr((char *)Platform_mqtt.cmdbuff,"{\"code\":\"1000\""); - if(ptr != NULL) - { - if(sscanf(ptr,"{\"code\":\"1000\",\"data\":{\"size\":%d,\"streamId\":%d,\"sign\":\"%*32s\",\"dProtocol\":\"mqtt\",\"version\":\"%11s\"",&AliOTA.size,&AliOTA.streamId,AliOTA.version)==3) - { - KPrintf("ota file size:%d\r\n",AliOTA.size); - KPrintf("ota file id:%d\r\n",AliOTA.streamId); - KPrintf("ota file version:%s\r\n",AliOTA.version); - if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,AliOTA.size != kStatus_Success)) - { - KPrintf("Failed to erase target fash!\n"); - ret = -1; - break; - } - AliOTA.counter = (AliOTA.size%FRAME_LEN != 0)? (AliOTA.size/FRAME_LEN + 1):(AliOTA.size/FRAME_LEN); - AliOTA.num = 1; //下载次数,初始值为1 - AliOTA.downlen = FRAME_LEN; //记录本次下载量 - OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 - } - else - { - KPrintf("Failed to get ota information!\n"); - ret = -1; - break; - } - } - - if(strstr((char *)Platform_mqtt.cmdbuff,"download_reply")) - { - memset(FrameBuf,0,sizeof(FrameBuf)); - memcpy(FrameBuf, &MqttRxbuf[datalen-AliOTA.downlen-2], AliOTA.downlen); - if(mcuboot.op_flash_write(flashdestination,FrameBuf,AliOTA.downlen) != kStatus_Success) - { - KPrintf("current frame[%d] flash failed.\n",AliOTA.num-1); - ret = -1; - break; - } - else - { - KPrintf("current frame[%d] is written to flash 0x%x address successful.\n", AliOTA.num -1, flashdestination); - KPrintf("Current progress is %d/%d\r\n",AliOTA.num,AliOTA.counter); - flashdestination += AliOTA.downlen; - AliOTA.num++; - } - - if(AliOTA.num < AliOTA.counter) //如果小于总下载次数 - { - AliOTA.downlen = FRAME_LEN; //记录本次下载量 - OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 - } - else if(AliOTA.num == AliOTA.counter) //如果等于总下载次数,说明是最后一次下载 - { - if(AliOTA.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍 - { - AliOTA.downlen = FRAME_LEN; //记录本次下载量 - OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 - } - else - { - AliOTA.downlen = AliOTA.size%FRAME_LEN; //记录本次下载量 - OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 - } - } - - else //下载完毕 - { - ret = 0; - break; - } - } - - } - else - { - freecnt = 0; - continue; - } - - if((freecnt >= 10) && (CalculateTimeMsFromTick(CurrentTicksGain()) - heart_time >= HEART_TIME)) //连续10次未收到数据默认为为空闲状态,需每隔一段时间发送需要发送心跳包保活 - { - heart_time = CalculateTimeMsFromTick(CurrentTicksGain()); - if(MQTT_SendHeart() != 0) //发送心跳包失败可能连接断开,需要重连 - { - KPrintf("The connection has been disconnected, reconnecting!\n"); - freecnt = 0; - heart_time = 0; - goto reconnect; - } - KPrintf("Send heartbeat packet successful!\n"); - } - } - - if(0 == ret) - { - ota_info.down.size = AliOTA.size; - ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, AliOTA.size); - - memset(ota_info.down.version,0,sizeof(ota_info.down.version)); - strncpy(ota_info.down.version, AliOTA.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); - } - 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); - } - MQTT_UnSubscribeTopic(topicdatabuff); - MQTT_Disconnect(); - mcuboot.flash_deinit(); - KPrintf("ota file transfer complete,start reboot!\n"); - MdelayKTask(2000); - mcuboot.op_reset(); -} - -int OtaTask(void) -{ - int32 ota_task = 0; - ota_task = KTaskCreate("ota_platform", app_ota_by_platform, NULL,8192, 10); - if(ota_task < 0) { - KPrintf("ota_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 10s !!!\r\n"); - - while(timeout) - { - ret = (SerialKeyPressed((uint8_t*)&ch1)); - if(ret) break; - timeout--; - mcuboot.op_delay(10); - } - - 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(); - } - } -} \ No newline at end of file